Merge "msm: kgsl: Remove the GMU power performance counters"
diff --git a/AndroidKernel.mk b/AndroidKernel.mk
index 3ab1fd8..f404b5a 100644
--- a/AndroidKernel.mk
+++ b/AndroidKernel.mk
@@ -162,14 +162,31 @@
echo $(KERNEL_CONFIG_OVERRIDE) >> $(KERNEL_OUT)/.config; \
$(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) oldconfig; fi
-$(TARGET_PREBUILT_INT_KERNEL): $(KERNEL_OUT) $(KERNEL_HEADERS_INSTALL)
+ifeq ($(TARGET_KERNEL_APPEND_DTB), true)
+TARGET_PREBUILT_INT_KERNEL_IMAGE := $(KERNEL_OUT)/arch/$(KERNEL_ARCH)/boot/Image
+$(TARGET_PREBUILT_INT_KERNEL_IMAGE): $(KERNEL_USR)
+$(TARGET_PREBUILT_INT_KERNEL_IMAGE): $(KERNEL_OUT) $(KERNEL_HEADERS_INSTALL)
+ $(hide) echo "Building kernel modules..."
+ $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) $(KERNEL_CFLAGS) Image
+ $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) $(KERNEL_CFLAGS) modules
+ $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) INSTALL_MOD_PATH=$(BUILD_ROOT_LOC)../$(KERNEL_MODULES_INSTALL) INSTALL_MOD_STRIP=1 $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) modules_install
+ $(mv-modules)
+ $(clean-module-folder)
+
+$(TARGET_PREBUILT_INT_KERNEL): $(TARGET_PREBUILT_INT_KERNEL_IMAGE)
$(hide) echo "Building kernel..."
$(hide) rm -rf $(KERNEL_OUT)/arch/$(KERNEL_ARCH)/boot/dts
$(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) $(KERNEL_CFLAGS)
+else
+TARGET_PREBUILT_INT_KERNEL_IMAGE := $(TARGET_PREBUILT_INT_KERNEL)
+$(TARGET_PREBUILT_INT_KERNEL): $(KERNEL_OUT) $(KERNEL_HEADERS_INSTALL)
+ $(hide) echo "Building kernel..."
+ $(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) $(KERNEL_CFLAGS)
$(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) $(KERNEL_CFLAGS) modules
$(MAKE) -C $(TARGET_KERNEL_SOURCE) O=$(BUILD_ROOT_LOC)$(KERNEL_OUT) INSTALL_MOD_PATH=$(BUILD_ROOT_LOC)../$(KERNEL_MODULES_INSTALL) INSTALL_MOD_STRIP=1 $(KERNEL_MAKE_ENV) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) $(real_cc) modules_install
$(mv-modules)
$(clean-module-folder)
+endif
$(KERNEL_HEADERS_INSTALL): $(KERNEL_OUT)
$(hide) if [ ! -z "$(KERNEL_HEADER_DEFCONFIG)" ]; then \
diff --git a/Documentation/ABI/testing/sysfs-class-net-qmi b/Documentation/ABI/testing/sysfs-class-net-qmi
index 7122d62..c310db4 100644
--- a/Documentation/ABI/testing/sysfs-class-net-qmi
+++ b/Documentation/ABI/testing/sysfs-class-net-qmi
@@ -29,7 +29,7 @@
Description:
Unsigned integer.
- Write a number ranging from 1 to 127 to add a qmap mux
+ Write a number ranging from 1 to 254 to add a qmap mux
based network device, supported by recent Qualcomm based
modems.
@@ -46,5 +46,5 @@
Description:
Unsigned integer.
- Write a number ranging from 1 to 127 to delete a previously
+ Write a number ranging from 1 to 254 to delete a previously
created qmap mux based network device.
diff --git a/Documentation/admin-guide/hw-vuln/index.rst b/Documentation/admin-guide/hw-vuln/index.rst
index ffc064c..49311f3 100644
--- a/Documentation/admin-guide/hw-vuln/index.rst
+++ b/Documentation/admin-guide/hw-vuln/index.rst
@@ -9,5 +9,6 @@
.. toctree::
:maxdepth: 1
+ spectre
l1tf
mds
diff --git a/Documentation/admin-guide/hw-vuln/spectre.rst b/Documentation/admin-guide/hw-vuln/spectre.rst
new file mode 100644
index 0000000..e05e581
--- /dev/null
+++ b/Documentation/admin-guide/hw-vuln/spectre.rst
@@ -0,0 +1,769 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Spectre Side Channels
+=====================
+
+Spectre is a class of side channel attacks that exploit branch prediction
+and speculative execution on modern CPUs to read memory, possibly
+bypassing access controls. Speculative execution side channel exploits
+do not modify memory but attempt to infer privileged data in the memory.
+
+This document covers Spectre variant 1 and Spectre variant 2.
+
+Affected processors
+-------------------
+
+Speculative execution side channel methods affect a wide range of modern
+high performance processors, since most modern high speed processors
+use branch prediction and speculative execution.
+
+The following CPUs are vulnerable:
+
+ - Intel Core, Atom, Pentium, and Xeon processors
+
+ - AMD Phenom, EPYC, and Zen processors
+
+ - IBM POWER and zSeries processors
+
+ - Higher end ARM processors
+
+ - Apple CPUs
+
+ - Higher end MIPS CPUs
+
+ - Likely most other high performance CPUs. Contact your CPU vendor for details.
+
+Whether a processor is affected or not can be read out from the Spectre
+vulnerability files in sysfs. See :ref:`spectre_sys_info`.
+
+Related CVEs
+------------
+
+The following CVE entries describe Spectre variants:
+
+ ============= ======================= ==========================
+ CVE-2017-5753 Bounds check bypass Spectre variant 1
+ CVE-2017-5715 Branch target injection Spectre variant 2
+ CVE-2019-1125 Spectre v1 swapgs Spectre variant 1 (swapgs)
+ ============= ======================= ==========================
+
+Problem
+-------
+
+CPUs use speculative operations to improve performance. That may leave
+traces of memory accesses or computations in the processor's caches,
+buffers, and branch predictors. Malicious software may be able to
+influence the speculative execution paths, and then use the side effects
+of the speculative execution in the CPUs' caches and buffers to infer
+privileged data touched during the speculative execution.
+
+Spectre variant 1 attacks take advantage of speculative execution of
+conditional branches, while Spectre variant 2 attacks use speculative
+execution of indirect branches to leak privileged memory.
+See :ref:`[1] <spec_ref1>` :ref:`[5] <spec_ref5>` :ref:`[7] <spec_ref7>`
+:ref:`[10] <spec_ref10>` :ref:`[11] <spec_ref11>`.
+
+Spectre variant 1 (Bounds Check Bypass)
+---------------------------------------
+
+The bounds check bypass attack :ref:`[2] <spec_ref2>` takes advantage
+of speculative execution that bypasses conditional branch instructions
+used for memory access bounds check (e.g. checking if the index of an
+array results in memory access within a valid range). This results in
+memory accesses to invalid memory (with out-of-bound index) that are
+done speculatively before validation checks resolve. Such speculative
+memory accesses can leave side effects, creating side channels which
+leak information to the attacker.
+
+There are some extensions of Spectre variant 1 attacks for reading data
+over the network, see :ref:`[12] <spec_ref12>`. However such attacks
+are difficult, low bandwidth, fragile, and are considered low risk.
+
+Note that, despite "Bounds Check Bypass" name, Spectre variant 1 is not
+only about user-controlled array bounds checks. It can affect any
+conditional checks. The kernel entry code interrupt, exception, and NMI
+handlers all have conditional swapgs checks. Those may be problematic
+in the context of Spectre v1, as kernel code can speculatively run with
+a user GS.
+
+Spectre variant 2 (Branch Target Injection)
+-------------------------------------------
+
+The branch target injection attack takes advantage of speculative
+execution of indirect branches :ref:`[3] <spec_ref3>`. The indirect
+branch predictors inside the processor used to guess the target of
+indirect branches can be influenced by an attacker, causing gadget code
+to be speculatively executed, thus exposing sensitive data touched by
+the victim. The side effects left in the CPU's caches during speculative
+execution can be measured to infer data values.
+
+.. _poison_btb:
+
+In Spectre variant 2 attacks, the attacker can steer speculative indirect
+branches in the victim to gadget code by poisoning the branch target
+buffer of a CPU used for predicting indirect branch addresses. Such
+poisoning could be done by indirect branching into existing code,
+with the address offset of the indirect branch under the attacker's
+control. Since the branch prediction on impacted hardware does not
+fully disambiguate branch address and uses the offset for prediction,
+this could cause privileged code's indirect branch to jump to a gadget
+code with the same offset.
+
+The most useful gadgets take an attacker-controlled input parameter (such
+as a register value) so that the memory read can be controlled. Gadgets
+without input parameters might be possible, but the attacker would have
+very little control over what memory can be read, reducing the risk of
+the attack revealing useful data.
+
+One other variant 2 attack vector is for the attacker to poison the
+return stack buffer (RSB) :ref:`[13] <spec_ref13>` to cause speculative
+subroutine return instruction execution to go to a gadget. An attacker's
+imbalanced subroutine call instructions might "poison" entries in the
+return stack buffer which are later consumed by a victim's subroutine
+return instructions. This attack can be mitigated by flushing the return
+stack buffer on context switch, or virtual machine (VM) exit.
+
+On systems with simultaneous multi-threading (SMT), attacks are possible
+from the sibling thread, as level 1 cache and branch target buffer
+(BTB) may be shared between hardware threads in a CPU core. A malicious
+program running on the sibling thread may influence its peer's BTB to
+steer its indirect branch speculations to gadget code, and measure the
+speculative execution's side effects left in level 1 cache to infer the
+victim's data.
+
+Attack scenarios
+----------------
+
+The following list of attack scenarios have been anticipated, but may
+not cover all possible attack vectors.
+
+1. A user process attacking the kernel
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Spectre variant 1
+~~~~~~~~~~~~~~~~~
+
+ The attacker passes a parameter to the kernel via a register or
+ via a known address in memory during a syscall. Such parameter may
+ be used later by the kernel as an index to an array or to derive
+ a pointer for a Spectre variant 1 attack. The index or pointer
+ is invalid, but bound checks are bypassed in the code branch taken
+ for speculative execution. This could cause privileged memory to be
+ accessed and leaked.
+
+ For kernel code that has been identified where data pointers could
+ potentially be influenced for Spectre attacks, new "nospec" accessor
+ macros are used to prevent speculative loading of data.
+
+Spectre variant 1 (swapgs)
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ An attacker can train the branch predictor to speculatively skip the
+ swapgs path for an interrupt or exception. If they initialize
+ the GS register to a user-space value, if the swapgs is speculatively
+ skipped, subsequent GS-related percpu accesses in the speculation
+ window will be done with the attacker-controlled GS value. This
+ could cause privileged memory to be accessed and leaked.
+
+ For example:
+
+ ::
+
+ if (coming from user space)
+ swapgs
+ mov %gs:<percpu_offset>, %reg
+ mov (%reg), %reg1
+
+ When coming from user space, the CPU can speculatively skip the
+ swapgs, and then do a speculative percpu load using the user GS
+ value. So the user can speculatively force a read of any kernel
+ value. If a gadget exists which uses the percpu value as an address
+ in another load/store, then the contents of the kernel value may
+ become visible via an L1 side channel attack.
+
+ A similar attack exists when coming from kernel space. The CPU can
+ speculatively do the swapgs, causing the user GS to get used for the
+ rest of the speculative window.
+
+Spectre variant 2
+~~~~~~~~~~~~~~~~~
+
+ A spectre variant 2 attacker can :ref:`poison <poison_btb>` the branch
+ target buffer (BTB) before issuing syscall to launch an attack.
+ After entering the kernel, the kernel could use the poisoned branch
+ target buffer on indirect jump and jump to gadget code in speculative
+ execution.
+
+ If an attacker tries to control the memory addresses leaked during
+ speculative execution, he would also need to pass a parameter to the
+ gadget, either through a register or a known address in memory. After
+ the gadget has executed, he can measure the side effect.
+
+ The kernel can protect itself against consuming poisoned branch
+ target buffer entries by using return trampolines (also known as
+ "retpoline") :ref:`[3] <spec_ref3>` :ref:`[9] <spec_ref9>` for all
+ indirect branches. Return trampolines trap speculative execution paths
+ to prevent jumping to gadget code during speculative execution.
+ x86 CPUs with Enhanced Indirect Branch Restricted Speculation
+ (Enhanced IBRS) available in hardware should use the feature to
+ mitigate Spectre variant 2 instead of retpoline. Enhanced IBRS is
+ more efficient than retpoline.
+
+ There may be gadget code in firmware which could be exploited with
+ Spectre variant 2 attack by a rogue user process. To mitigate such
+ attacks on x86, Indirect Branch Restricted Speculation (IBRS) feature
+ is turned on before the kernel invokes any firmware code.
+
+2. A user process attacking another user process
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ A malicious user process can try to attack another user process,
+ either via a context switch on the same hardware thread, or from the
+ sibling hyperthread sharing a physical processor core on simultaneous
+ multi-threading (SMT) system.
+
+ Spectre variant 1 attacks generally require passing parameters
+ between the processes, which needs a data passing relationship, such
+ as remote procedure calls (RPC). Those parameters are used in gadget
+ code to derive invalid data pointers accessing privileged memory in
+ the attacked process.
+
+ Spectre variant 2 attacks can be launched from a rogue process by
+ :ref:`poisoning <poison_btb>` the branch target buffer. This can
+ influence the indirect branch targets for a victim process that either
+ runs later on the same hardware thread, or running concurrently on
+ a sibling hardware thread sharing the same physical core.
+
+ A user process can protect itself against Spectre variant 2 attacks
+ by using the prctl() syscall to disable indirect branch speculation
+ for itself. An administrator can also cordon off an unsafe process
+ from polluting the branch target buffer by disabling the process's
+ indirect branch speculation. This comes with a performance cost
+ from not using indirect branch speculation and clearing the branch
+ target buffer. When SMT is enabled on x86, for a process that has
+ indirect branch speculation disabled, Single Threaded Indirect Branch
+ Predictors (STIBP) :ref:`[4] <spec_ref4>` are turned on to prevent the
+ sibling thread from controlling branch target buffer. In addition,
+ the Indirect Branch Prediction Barrier (IBPB) is issued to clear the
+ branch target buffer when context switching to and from such process.
+
+ On x86, the return stack buffer is stuffed on context switch.
+ This prevents the branch target buffer from being used for branch
+ prediction when the return stack buffer underflows while switching to
+ a deeper call stack. Any poisoned entries in the return stack buffer
+ left by the previous process will also be cleared.
+
+ User programs should use address space randomization to make attacks
+ more difficult (Set /proc/sys/kernel/randomize_va_space = 1 or 2).
+
+3. A virtualized guest attacking the host
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ The attack mechanism is similar to how user processes attack the
+ kernel. The kernel is entered via hyper-calls or other virtualization
+ exit paths.
+
+ For Spectre variant 1 attacks, rogue guests can pass parameters
+ (e.g. in registers) via hyper-calls to derive invalid pointers to
+ speculate into privileged memory after entering the kernel. For places
+ where such kernel code has been identified, nospec accessor macros
+ are used to stop speculative memory access.
+
+ For Spectre variant 2 attacks, rogue guests can :ref:`poison
+ <poison_btb>` the branch target buffer or return stack buffer, causing
+ the kernel to jump to gadget code in the speculative execution paths.
+
+ To mitigate variant 2, the host kernel can use return trampolines
+ for indirect branches to bypass the poisoned branch target buffer,
+ and flushing the return stack buffer on VM exit. This prevents rogue
+ guests from affecting indirect branching in the host kernel.
+
+ To protect host processes from rogue guests, host processes can have
+ indirect branch speculation disabled via prctl(). The branch target
+ buffer is cleared before context switching to such processes.
+
+4. A virtualized guest attacking other guest
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ A rogue guest may attack another guest to get data accessible by the
+ other guest.
+
+ Spectre variant 1 attacks are possible if parameters can be passed
+ between guests. This may be done via mechanisms such as shared memory
+ or message passing. Such parameters could be used to derive data
+ pointers to privileged data in guest. The privileged data could be
+ accessed by gadget code in the victim's speculation paths.
+
+ Spectre variant 2 attacks can be launched from a rogue guest by
+ :ref:`poisoning <poison_btb>` the branch target buffer or the return
+ stack buffer. Such poisoned entries could be used to influence
+ speculation execution paths in the victim guest.
+
+ Linux kernel mitigates attacks to other guests running in the same
+ CPU hardware thread by flushing the return stack buffer on VM exit,
+ and clearing the branch target buffer before switching to a new guest.
+
+ If SMT is used, Spectre variant 2 attacks from an untrusted guest
+ in the sibling hyperthread can be mitigated by the administrator,
+ by turning off the unsafe guest's indirect branch speculation via
+ prctl(). A guest can also protect itself by turning on microcode
+ based mitigations (such as IBPB or STIBP on x86) within the guest.
+
+.. _spectre_sys_info:
+
+Spectre system information
+--------------------------
+
+The Linux kernel provides a sysfs interface to enumerate the current
+mitigation status of the system for Spectre: whether the system is
+vulnerable, and which mitigations are active.
+
+The sysfs file showing Spectre variant 1 mitigation status is:
+
+ /sys/devices/system/cpu/vulnerabilities/spectre_v1
+
+The possible values in this file are:
+
+ .. list-table::
+
+ * - 'Not affected'
+ - The processor is not vulnerable.
+ * - 'Vulnerable: __user pointer sanitization and usercopy barriers only; no swapgs barriers'
+ - The swapgs protections are disabled; otherwise it has
+ protection in the kernel on a case by case base with explicit
+ pointer sanitation and usercopy LFENCE barriers.
+ * - 'Mitigation: usercopy/swapgs barriers and __user pointer sanitization'
+ - Protection in the kernel on a case by case base with explicit
+ pointer sanitation, usercopy LFENCE barriers, and swapgs LFENCE
+ barriers.
+
+However, the protections are put in place on a case by case basis,
+and there is no guarantee that all possible attack vectors for Spectre
+variant 1 are covered.
+
+The spectre_v2 kernel file reports if the kernel has been compiled with
+retpoline mitigation or if the CPU has hardware mitigation, and if the
+CPU has support for additional process-specific mitigation.
+
+This file also reports CPU features enabled by microcode to mitigate
+attack between user processes:
+
+1. Indirect Branch Prediction Barrier (IBPB) to add additional
+ isolation between processes of different users.
+2. Single Thread Indirect Branch Predictors (STIBP) to add additional
+ isolation between CPU threads running on the same core.
+
+These CPU features may impact performance when used and can be enabled
+per process on a case-by-case base.
+
+The sysfs file showing Spectre variant 2 mitigation status is:
+
+ /sys/devices/system/cpu/vulnerabilities/spectre_v2
+
+The possible values in this file are:
+
+ - Kernel status:
+
+ ==================================== =================================
+ 'Not affected' The processor is not vulnerable
+ 'Vulnerable' Vulnerable, no mitigation
+ 'Mitigation: Full generic retpoline' Software-focused mitigation
+ 'Mitigation: Full AMD retpoline' AMD-specific software mitigation
+ 'Mitigation: Enhanced IBRS' Hardware-focused mitigation
+ ==================================== =================================
+
+ - Firmware status: Show if Indirect Branch Restricted Speculation (IBRS) is
+ used to protect against Spectre variant 2 attacks when calling firmware (x86 only).
+
+ ========== =============================================================
+ 'IBRS_FW' Protection against user program attacks when calling firmware
+ ========== =============================================================
+
+ - Indirect branch prediction barrier (IBPB) status for protection between
+ processes of different users. This feature can be controlled through
+ prctl() per process, or through kernel command line options. This is
+ an x86 only feature. For more details see below.
+
+ =================== ========================================================
+ 'IBPB: disabled' IBPB unused
+ 'IBPB: always-on' Use IBPB on all tasks
+ 'IBPB: conditional' Use IBPB on SECCOMP or indirect branch restricted tasks
+ =================== ========================================================
+
+ - Single threaded indirect branch prediction (STIBP) status for protection
+ between different hyper threads. This feature can be controlled through
+ prctl per process, or through kernel command line options. This is x86
+ only feature. For more details see below.
+
+ ==================== ========================================================
+ 'STIBP: disabled' STIBP unused
+ 'STIBP: forced' Use STIBP on all tasks
+ 'STIBP: conditional' Use STIBP on SECCOMP or indirect branch restricted tasks
+ ==================== ========================================================
+
+ - Return stack buffer (RSB) protection status:
+
+ ============= ===========================================
+ 'RSB filling' Protection of RSB on context switch enabled
+ ============= ===========================================
+
+Full mitigation might require a microcode update from the CPU
+vendor. When the necessary microcode is not available, the kernel will
+report vulnerability.
+
+Turning on mitigation for Spectre variant 1 and Spectre variant 2
+-----------------------------------------------------------------
+
+1. Kernel mitigation
+^^^^^^^^^^^^^^^^^^^^
+
+Spectre variant 1
+~~~~~~~~~~~~~~~~~
+
+ For the Spectre variant 1, vulnerable kernel code (as determined
+ by code audit or scanning tools) is annotated on a case by case
+ basis to use nospec accessor macros for bounds clipping :ref:`[2]
+ <spec_ref2>` to avoid any usable disclosure gadgets. However, it may
+ not cover all attack vectors for Spectre variant 1.
+
+ Copy-from-user code has an LFENCE barrier to prevent the access_ok()
+ check from being mis-speculated. The barrier is done by the
+ barrier_nospec() macro.
+
+ For the swapgs variant of Spectre variant 1, LFENCE barriers are
+ added to interrupt, exception and NMI entry where needed. These
+ barriers are done by the FENCE_SWAPGS_KERNEL_ENTRY and
+ FENCE_SWAPGS_USER_ENTRY macros.
+
+Spectre variant 2
+~~~~~~~~~~~~~~~~~
+
+ For Spectre variant 2 mitigation, the compiler turns indirect calls or
+ jumps in the kernel into equivalent return trampolines (retpolines)
+ :ref:`[3] <spec_ref3>` :ref:`[9] <spec_ref9>` to go to the target
+ addresses. Speculative execution paths under retpolines are trapped
+ in an infinite loop to prevent any speculative execution jumping to
+ a gadget.
+
+ To turn on retpoline mitigation on a vulnerable CPU, the kernel
+ needs to be compiled with a gcc compiler that supports the
+ -mindirect-branch=thunk-extern -mindirect-branch-register options.
+ If the kernel is compiled with a Clang compiler, the compiler needs
+ to support -mretpoline-external-thunk option. The kernel config
+ CONFIG_RETPOLINE needs to be turned on, and the CPU needs to run with
+ the latest updated microcode.
+
+ On Intel Skylake-era systems the mitigation covers most, but not all,
+ cases. See :ref:`[3] <spec_ref3>` for more details.
+
+ On CPUs with hardware mitigation for Spectre variant 2 (e.g. Enhanced
+ IBRS on x86), retpoline is automatically disabled at run time.
+
+ The retpoline mitigation is turned on by default on vulnerable
+ CPUs. It can be forced on or off by the administrator
+ via the kernel command line and sysfs control files. See
+ :ref:`spectre_mitigation_control_command_line`.
+
+ On x86, indirect branch restricted speculation is turned on by default
+ before invoking any firmware code to prevent Spectre variant 2 exploits
+ using the firmware.
+
+ Using kernel address space randomization (CONFIG_RANDOMIZE_SLAB=y
+ and CONFIG_SLAB_FREELIST_RANDOM=y in the kernel configuration) makes
+ attacks on the kernel generally more difficult.
+
+2. User program mitigation
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ User programs can mitigate Spectre variant 1 using LFENCE or "bounds
+ clipping". For more details see :ref:`[2] <spec_ref2>`.
+
+ For Spectre variant 2 mitigation, individual user programs
+ can be compiled with return trampolines for indirect branches.
+ This protects them from consuming poisoned entries in the branch
+ target buffer left by malicious software. Alternatively, the
+ programs can disable their indirect branch speculation via prctl()
+ (See :ref:`Documentation/userspace-api/spec_ctrl.rst <set_spec_ctrl>`).
+ On x86, this will turn on STIBP to guard against attacks from the
+ sibling thread when the user program is running, and use IBPB to
+ flush the branch target buffer when switching to/from the program.
+
+ Restricting indirect branch speculation on a user program will
+ also prevent the program from launching a variant 2 attack
+ on x86. All sand-boxed SECCOMP programs have indirect branch
+ speculation restricted by default. Administrators can change
+ that behavior via the kernel command line and sysfs control files.
+ See :ref:`spectre_mitigation_control_command_line`.
+
+ Programs that disable their indirect branch speculation will have
+ more overhead and run slower.
+
+ User programs should use address space randomization
+ (/proc/sys/kernel/randomize_va_space = 1 or 2) to make attacks more
+ difficult.
+
+3. VM mitigation
+^^^^^^^^^^^^^^^^
+
+ Within the kernel, Spectre variant 1 attacks from rogue guests are
+ mitigated on a case by case basis in VM exit paths. Vulnerable code
+ uses nospec accessor macros for "bounds clipping", to avoid any
+ usable disclosure gadgets. However, this may not cover all variant
+ 1 attack vectors.
+
+ For Spectre variant 2 attacks from rogue guests to the kernel, the
+ Linux kernel uses retpoline or Enhanced IBRS to prevent consumption of
+ poisoned entries in branch target buffer left by rogue guests. It also
+ flushes the return stack buffer on every VM exit to prevent a return
+ stack buffer underflow so poisoned branch target buffer could be used,
+ or attacker guests leaving poisoned entries in the return stack buffer.
+
+ To mitigate guest-to-guest attacks in the same CPU hardware thread,
+ the branch target buffer is sanitized by flushing before switching
+ to a new guest on a CPU.
+
+ The above mitigations are turned on by default on vulnerable CPUs.
+
+ To mitigate guest-to-guest attacks from sibling thread when SMT is
+ in use, an untrusted guest running in the sibling thread can have
+ its indirect branch speculation disabled by administrator via prctl().
+
+ The kernel also allows guests to use any microcode based mitigation
+ they choose to use (such as IBPB or STIBP on x86) to protect themselves.
+
+.. _spectre_mitigation_control_command_line:
+
+Mitigation control on the kernel command line
+---------------------------------------------
+
+Spectre variant 2 mitigation can be disabled or force enabled at the
+kernel command line.
+
+ nospectre_v1
+
+ [X86,PPC] Disable mitigations for Spectre Variant 1
+ (bounds check bypass). With this option data leaks are
+ possible in the system.
+
+ nospectre_v2
+
+ [X86] Disable all mitigations for the Spectre variant 2
+ (indirect branch prediction) vulnerability. System may
+ allow data leaks with this option, which is equivalent
+ to spectre_v2=off.
+
+
+ spectre_v2=
+
+ [X86] Control mitigation of Spectre variant 2
+ (indirect branch speculation) vulnerability.
+ The default operation protects the kernel from
+ user space attacks.
+
+ on
+ unconditionally enable, implies
+ spectre_v2_user=on
+ off
+ unconditionally disable, implies
+ spectre_v2_user=off
+ auto
+ kernel detects whether your CPU model is
+ vulnerable
+
+ Selecting 'on' will, and 'auto' may, choose a
+ mitigation method at run time according to the
+ CPU, the available microcode, the setting of the
+ CONFIG_RETPOLINE configuration option, and the
+ compiler with which the kernel was built.
+
+ Selecting 'on' will also enable the mitigation
+ against user space to user space task attacks.
+
+ Selecting 'off' will disable both the kernel and
+ the user space protections.
+
+ Specific mitigations can also be selected manually:
+
+ retpoline
+ replace indirect branches
+ retpoline,generic
+ google's original retpoline
+ retpoline,amd
+ AMD-specific minimal thunk
+
+ Not specifying this option is equivalent to
+ spectre_v2=auto.
+
+For user space mitigation:
+
+ spectre_v2_user=
+
+ [X86] Control mitigation of Spectre variant 2
+ (indirect branch speculation) vulnerability between
+ user space tasks
+
+ on
+ Unconditionally enable mitigations. Is
+ enforced by spectre_v2=on
+
+ off
+ Unconditionally disable mitigations. Is
+ enforced by spectre_v2=off
+
+ prctl
+ Indirect branch speculation is enabled,
+ but mitigation can be enabled via prctl
+ per thread. The mitigation control state
+ is inherited on fork.
+
+ prctl,ibpb
+ Like "prctl" above, but only STIBP is
+ controlled per thread. IBPB is issued
+ always when switching between different user
+ space processes.
+
+ seccomp
+ Same as "prctl" above, but all seccomp
+ threads will enable the mitigation unless
+ they explicitly opt out.
+
+ seccomp,ibpb
+ Like "seccomp" above, but only STIBP is
+ controlled per thread. IBPB is issued
+ always when switching between different
+ user space processes.
+
+ auto
+ Kernel selects the mitigation depending on
+ the available CPU features and vulnerability.
+
+ Default mitigation:
+ If CONFIG_SECCOMP=y then "seccomp", otherwise "prctl"
+
+ Not specifying this option is equivalent to
+ spectre_v2_user=auto.
+
+ In general the kernel by default selects
+ reasonable mitigations for the current CPU. To
+ disable Spectre variant 2 mitigations, boot with
+ spectre_v2=off. Spectre variant 1 mitigations
+ cannot be disabled.
+
+Mitigation selection guide
+--------------------------
+
+1. Trusted userspace
+^^^^^^^^^^^^^^^^^^^^
+
+ If all userspace applications are from trusted sources and do not
+ execute externally supplied untrusted code, then the mitigations can
+ be disabled.
+
+2. Protect sensitive programs
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ For security-sensitive programs that have secrets (e.g. crypto
+ keys), protection against Spectre variant 2 can be put in place by
+ disabling indirect branch speculation when the program is running
+ (See :ref:`Documentation/userspace-api/spec_ctrl.rst <set_spec_ctrl>`).
+
+3. Sandbox untrusted programs
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ Untrusted programs that could be a source of attacks can be cordoned
+ off by disabling their indirect branch speculation when they are run
+ (See :ref:`Documentation/userspace-api/spec_ctrl.rst <set_spec_ctrl>`).
+ This prevents untrusted programs from polluting the branch target
+ buffer. All programs running in SECCOMP sandboxes have indirect
+ branch speculation restricted by default. This behavior can be
+ changed via the kernel command line and sysfs control files. See
+ :ref:`spectre_mitigation_control_command_line`.
+
+3. High security mode
+^^^^^^^^^^^^^^^^^^^^^
+
+ All Spectre variant 2 mitigations can be forced on
+ at boot time for all programs (See the "on" option in
+ :ref:`spectre_mitigation_control_command_line`). This will add
+ overhead as indirect branch speculations for all programs will be
+ restricted.
+
+ On x86, branch target buffer will be flushed with IBPB when switching
+ to a new program. STIBP is left on all the time to protect programs
+ against variant 2 attacks originating from programs running on
+ sibling threads.
+
+ Alternatively, STIBP can be used only when running programs
+ whose indirect branch speculation is explicitly disabled,
+ while IBPB is still used all the time when switching to a new
+ program to clear the branch target buffer (See "ibpb" option in
+ :ref:`spectre_mitigation_control_command_line`). This "ibpb" option
+ has less performance cost than the "on" option, which leaves STIBP
+ on all the time.
+
+References on Spectre
+---------------------
+
+Intel white papers:
+
+.. _spec_ref1:
+
+[1] `Intel analysis of speculative execution side channels <https://newsroom.intel.com/wp-content/uploads/sites/11/2018/01/Intel-Analysis-of-Speculative-Execution-Side-Channels.pdf>`_.
+
+.. _spec_ref2:
+
+[2] `Bounds check bypass <https://software.intel.com/security-software-guidance/software-guidance/bounds-check-bypass>`_.
+
+.. _spec_ref3:
+
+[3] `Deep dive: Retpoline: A branch target injection mitigation <https://software.intel.com/security-software-guidance/insights/deep-dive-retpoline-branch-target-injection-mitigation>`_.
+
+.. _spec_ref4:
+
+[4] `Deep Dive: Single Thread Indirect Branch Predictors <https://software.intel.com/security-software-guidance/insights/deep-dive-single-thread-indirect-branch-predictors>`_.
+
+AMD white papers:
+
+.. _spec_ref5:
+
+[5] `AMD64 technology indirect branch control extension <https://developer.amd.com/wp-content/resources/Architecture_Guidelines_Update_Indirect_Branch_Control.pdf>`_.
+
+.. _spec_ref6:
+
+[6] `Software techniques for managing speculation on AMD processors <https://developer.amd.com/wp-content/resources/90343-B_SoftwareTechniquesforManagingSpeculation_WP_7-18Update_FNL.pdf>`_.
+
+ARM white papers:
+
+.. _spec_ref7:
+
+[7] `Cache speculation side-channels <https://developer.arm.com/support/arm-security-updates/speculative-processor-vulnerability/download-the-whitepaper>`_.
+
+.. _spec_ref8:
+
+[8] `Cache speculation issues update <https://developer.arm.com/support/arm-security-updates/speculative-processor-vulnerability/latest-updates/cache-speculation-issues-update>`_.
+
+Google white paper:
+
+.. _spec_ref9:
+
+[9] `Retpoline: a software construct for preventing branch-target-injection <https://support.google.com/faqs/answer/7625886>`_.
+
+MIPS white paper:
+
+.. _spec_ref10:
+
+[10] `MIPS: response on speculative execution and side channel vulnerabilities <https://www.mips.com/blog/mips-response-on-speculative-execution-and-side-channel-vulnerabilities/>`_.
+
+Academic papers:
+
+.. _spec_ref11:
+
+[11] `Spectre Attacks: Exploiting Speculative Execution <https://spectreattack.com/spectre.pdf>`_.
+
+.. _spec_ref12:
+
+[12] `NetSpectre: Read Arbitrary Memory over Network <https://arxiv.org/abs/1807.10535>`_.
+
+.. _spec_ref13:
+
+[13] `Spectre Returns! Speculation Attacks using the Return Stack Buffer <https://www.usenix.org/system/files/conference/woot18/woot18-paper-koruyeh.pdf>`_.
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 0706064..fab641a 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -2522,6 +2522,7 @@
Equivalent to: nopti [X86,PPC]
nospectre_v1 [PPC]
nobp=0 [S390]
+ nospectre_v1 [X86]
nospectre_v2 [X86,PPC,S390]
spectre_v2_user=off [X86]
spec_store_bypass_disable=off [X86,PPC]
@@ -2868,9 +2869,9 @@
nosmt=force: Force disable SMT, cannot be undone
via the sysfs control file.
- nospectre_v1 [PPC] Disable mitigations for Spectre Variant 1 (bounds
- check bypass). With this option data leaks are possible
- in the system.
+ nospectre_v1 [X66, PPC] Disable mitigations for Spectre Variant 1
+ (bounds check bypass). With this option data leaks
+ are possible in the system.
nospectre_v2 [X86,PPC_FSL_BOOK3E] Disable all mitigations for the Spectre variant 2
(indirect branch prediction) vulnerability. System may
@@ -4989,12 +4990,6 @@
emulate [default] Vsyscalls turn into traps and are
emulated reasonably safely.
- native Vsyscalls are native syscall instructions.
- This is a little bit faster than trapping
- and makes a few dynamic recompilers work
- better than they would in emulation mode.
- It also makes exploits much easier to write.
-
none Vsyscalls don't work at all. This makes
them quite hard to use for exploits but
might break your system.
diff --git a/Documentation/atomic_t.txt b/Documentation/atomic_t.txt
index 913396a..ed0d814 100644
--- a/Documentation/atomic_t.txt
+++ b/Documentation/atomic_t.txt
@@ -177,6 +177,9 @@
ordering on their SMP atomic primitives. For example our TSO architectures
provide full ordered atomics and these barriers are no-ops.
+NOTE: when the atomic RmW ops are fully ordered, they should also imply a
+compiler barrier.
+
Thus:
atomic_fetch_add();
diff --git a/Documentation/scheduler/sched-pelt.c b/Documentation/scheduler/sched-pelt.c
index e421913..7238b35 100644
--- a/Documentation/scheduler/sched-pelt.c
+++ b/Documentation/scheduler/sched-pelt.c
@@ -20,7 +20,8 @@ void calc_runnable_avg_yN_inv(void)
int i;
unsigned int x;
- printf("static const u32 runnable_avg_yN_inv[] = {");
+ /* To silence -Wunused-but-set-variable warnings. */
+ printf("static const u32 runnable_avg_yN_inv[] __maybe_unused = {");
for (i = 0; i < HALFLIFE; i++) {
x = ((1UL<<32)-1)*pow(y, i);
diff --git a/Documentation/userspace-api/spec_ctrl.rst b/Documentation/userspace-api/spec_ctrl.rst
index c4dbe6f..0fda8f6 100644
--- a/Documentation/userspace-api/spec_ctrl.rst
+++ b/Documentation/userspace-api/spec_ctrl.rst
@@ -47,6 +47,8 @@
available. If not set, prctl(PR_SET_SPECULATION_CTRL) for the speculation
misfeature will fail.
+.. _set_spec_ctrl:
+
PR_SET_SPECULATION_CTRL
-----------------------
diff --git a/Makefile b/Makefile
index 0099f5c..47b7619 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
VERSION = 4
PATCHLEVEL = 19
-SUBLEVEL = 58
+SUBLEVEL = 66
EXTRAVERSION =
NAME = "People's Front"
@@ -434,6 +434,7 @@
KBUILD_LDFLAGS_MODULE := -T $(srctree)/scripts/module-common.lds
KBUILD_LDFLAGS :=
GCC_PLUGINS_CFLAGS :=
+CLANG_FLAGS :=
export ARCH SRCARCH CONFIG_SHELL HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE AS LD CC
export CPP AR NM STRIP OBJCOPY OBJDUMP KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS
@@ -487,7 +488,7 @@
ifeq ($(cc-name),clang)
ifneq ($(CROSS_COMPILE),)
CLANG_TRIPLE ?= $(CROSS_COMPILE)
-CLANG_FLAGS := --target=$(notdir $(CLANG_TRIPLE:%-=%))
+CLANG_FLAGS += --target=$(notdir $(CLANG_TRIPLE:%-=%))
ifeq ($(shell $(srctree)/scripts/clang-android.sh $(CC) $(CLANG_FLAGS)), y)
$(error "Clang with Android --target detected. Did you specify CLANG_TRIPLE?")
endif
@@ -499,6 +500,7 @@
CLANG_FLAGS += --gcc-toolchain=$(GCC_TOOLCHAIN)
endif
CLANG_FLAGS += -no-integrated-as
+CLANG_FLAGS += -Werror=unknown-warning-option
KBUILD_CFLAGS += $(CLANG_FLAGS)
KBUILD_AFLAGS += $(CLANG_FLAGS)
export CLANG_FLAGS
diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig
index 74953e7..0cce541 100644
--- a/arch/arc/Kconfig
+++ b/arch/arc/Kconfig
@@ -199,7 +199,6 @@
config ARC_SMP_HALT_ON_RESET
bool "Enable Halt-on-reset boot mode"
- default y if ARC_UBOOT_SUPPORT
help
In SMP configuration cores can be configured as Halt-on-reset
or they could all start at same time. For Halt-on-reset, non
@@ -539,18 +538,6 @@
endif
-config ARC_UBOOT_SUPPORT
- bool "Support uboot arg Handling"
- default n
- help
- ARC Linux by default checks for uboot provided args as pointers to
- external cmdline or DTB. This however breaks in absence of uboot,
- when booting from Metaware debugger directly, as the registers are
- not zeroed out on reset by mdb and/or ARCv2 based cores. The bogus
- registers look like uboot args to kernel which then chokes.
- So only enable the uboot arg checking/processing if users are sure
- of uboot being in play.
-
config ARC_BUILTIN_DTB_NAME
string "Built in DTB"
help
diff --git a/arch/arc/configs/nps_defconfig b/arch/arc/configs/nps_defconfig
index 6e84060..621f594 100644
--- a/arch/arc/configs/nps_defconfig
+++ b/arch/arc/configs/nps_defconfig
@@ -31,7 +31,6 @@
# CONFIG_ARC_HAS_LLSC is not set
CONFIG_ARC_KVADDR_SIZE=402
CONFIG_ARC_EMUL_UNALIGNED=y
-CONFIG_ARC_UBOOT_SUPPORT=y
CONFIG_PREEMPT=y
CONFIG_NET=y
CONFIG_UNIX=y
diff --git a/arch/arc/configs/vdk_hs38_defconfig b/arch/arc/configs/vdk_hs38_defconfig
index 1e59a2e..e447ace6 100644
--- a/arch/arc/configs/vdk_hs38_defconfig
+++ b/arch/arc/configs/vdk_hs38_defconfig
@@ -13,7 +13,6 @@
CONFIG_ARC_PLAT_AXS10X=y
CONFIG_AXS103=y
CONFIG_ISA_ARCV2=y
-CONFIG_ARC_UBOOT_SUPPORT=y
CONFIG_ARC_BUILTIN_DTB_NAME="vdk_hs38"
CONFIG_PREEMPT=y
CONFIG_NET=y
diff --git a/arch/arc/configs/vdk_hs38_smp_defconfig b/arch/arc/configs/vdk_hs38_smp_defconfig
index b5c3f6c..c82cdb1 100644
--- a/arch/arc/configs/vdk_hs38_smp_defconfig
+++ b/arch/arc/configs/vdk_hs38_smp_defconfig
@@ -15,8 +15,6 @@
CONFIG_ISA_ARCV2=y
CONFIG_SMP=y
# CONFIG_ARC_TIMERS_64BIT is not set
-# CONFIG_ARC_SMP_HALT_ON_RESET is not set
-CONFIG_ARC_UBOOT_SUPPORT=y
CONFIG_ARC_BUILTIN_DTB_NAME="vdk_hs38_smp"
CONFIG_PREEMPT=y
CONFIG_NET=y
diff --git a/arch/arc/kernel/head.S b/arch/arc/kernel/head.S
index 208bf2c..a72bbda 100644
--- a/arch/arc/kernel/head.S
+++ b/arch/arc/kernel/head.S
@@ -100,7 +100,6 @@
st.ab 0, [r5, 4]
1:
-#ifdef CONFIG_ARC_UBOOT_SUPPORT
; Uboot - kernel ABI
; r0 = [0] No uboot interaction, [1] cmdline in r2, [2] DTB in r2
; r1 = magic number (always zero as of now)
@@ -109,7 +108,6 @@
st r0, [@uboot_tag]
st r1, [@uboot_magic]
st r2, [@uboot_arg]
-#endif
; setup "current" tsk and optionally cache it in dedicated r25
mov r9, @init_task
diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c
index a121893..89c97dc 100644
--- a/arch/arc/kernel/setup.c
+++ b/arch/arc/kernel/setup.c
@@ -493,7 +493,6 @@ void __init handle_uboot_args(void)
bool use_embedded_dtb = true;
bool append_cmdline = false;
-#ifdef CONFIG_ARC_UBOOT_SUPPORT
/* check that we know this tag */
if (uboot_tag != UBOOT_TAG_NONE &&
uboot_tag != UBOOT_TAG_CMDLINE &&
@@ -525,7 +524,6 @@ void __init handle_uboot_args(void)
append_cmdline = true;
ignore_uboot_args:
-#endif
if (use_embedded_dtb) {
machine_desc = setup_machine_fdt(__dtb_start);
diff --git a/arch/arc/kernel/unwind.c b/arch/arc/kernel/unwind.c
index 183391d..9cf2ee8 100644
--- a/arch/arc/kernel/unwind.c
+++ b/arch/arc/kernel/unwind.c
@@ -185,11 +185,6 @@ static void *__init unw_hdr_alloc_early(unsigned long sz)
MAX_DMA_ADDRESS);
}
-static void *unw_hdr_alloc(unsigned long sz)
-{
- return kmalloc(sz, GFP_KERNEL);
-}
-
static void init_unwind_table(struct unwind_table *table, const char *name,
const void *core_start, unsigned long core_size,
const void *init_start, unsigned long init_size,
@@ -370,6 +365,10 @@ static void init_unwind_hdr(struct unwind_table *table,
}
#ifdef CONFIG_MODULES
+static void *unw_hdr_alloc(unsigned long sz)
+{
+ return kmalloc(sz, GFP_KERNEL);
+}
static struct unwind_table *last_table;
diff --git a/arch/arm/boot/dts/am335x-pcm-953.dtsi b/arch/arm/boot/dts/am335x-pcm-953.dtsi
index 1ec8e0d..572fbd2 100644
--- a/arch/arm/boot/dts/am335x-pcm-953.dtsi
+++ b/arch/arm/boot/dts/am335x-pcm-953.dtsi
@@ -197,7 +197,7 @@
bus-width = <4>;
pinctrl-names = "default";
pinctrl-0 = <&mmc1_pins>;
- cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
+ cd-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/am335x-wega.dtsi b/arch/arm/boot/dts/am335x-wega.dtsi
index 8ce5417..83e4fe5 100644
--- a/arch/arm/boot/dts/am335x-wega.dtsi
+++ b/arch/arm/boot/dts/am335x-wega.dtsi
@@ -157,7 +157,7 @@
bus-width = <4>;
pinctrl-names = "default";
pinctrl-0 = <&mmc1_pins>;
- cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
+ cd-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/gemini-dlink-dns-313.dts b/arch/arm/boot/dts/gemini-dlink-dns-313.dts
index d132932..361dccd 100644
--- a/arch/arm/boot/dts/gemini-dlink-dns-313.dts
+++ b/arch/arm/boot/dts/gemini-dlink-dns-313.dts
@@ -11,7 +11,7 @@
/ {
model = "D-Link DNS-313 1-Bay Network Storage Enclosure";
- compatible = "dlink,dir-313", "cortina,gemini";
+ compatible = "dlink,dns-313", "cortina,gemini";
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/imx6ul.dtsi b/arch/arm/boot/dts/imx6ul.dtsi
index 2366f09..336cdea 100644
--- a/arch/arm/boot/dts/imx6ul.dtsi
+++ b/arch/arm/boot/dts/imx6ul.dtsi
@@ -359,7 +359,7 @@
pwm1: pwm@2080000 {
compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
reg = <0x02080000 0x4000>;
- interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_PWM1>,
<&clks IMX6UL_CLK_PWM1>;
clock-names = "ipg", "per";
@@ -370,7 +370,7 @@
pwm2: pwm@2084000 {
compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
reg = <0x02084000 0x4000>;
- interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_PWM2>,
<&clks IMX6UL_CLK_PWM2>;
clock-names = "ipg", "per";
@@ -381,7 +381,7 @@
pwm3: pwm@2088000 {
compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
reg = <0x02088000 0x4000>;
- interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_PWM3>,
<&clks IMX6UL_CLK_PWM3>;
clock-names = "ipg", "per";
@@ -392,7 +392,7 @@
pwm4: pwm@208c000 {
compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
reg = <0x0208c000 0x4000>;
- interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_PWM4>,
<&clks IMX6UL_CLK_PWM4>;
clock-names = "ipg", "per";
diff --git a/arch/arm/boot/dts/rk3288-veyron-mickey.dts b/arch/arm/boot/dts/rk3288-veyron-mickey.dts
index 1e0158a..a593d0a 100644
--- a/arch/arm/boot/dts/rk3288-veyron-mickey.dts
+++ b/arch/arm/boot/dts/rk3288-veyron-mickey.dts
@@ -124,10 +124,6 @@
};
};
-&emmc {
- /delete-property/mmc-hs200-1_8v;
-};
-
&i2c2 {
status = "disabled";
};
diff --git a/arch/arm/boot/dts/rk3288-veyron-minnie.dts b/arch/arm/boot/dts/rk3288-veyron-minnie.dts
index f95d0c5..6e89460 100644
--- a/arch/arm/boot/dts/rk3288-veyron-minnie.dts
+++ b/arch/arm/boot/dts/rk3288-veyron-minnie.dts
@@ -90,10 +90,6 @@
pwm-off-delay-ms = <200>;
};
-&emmc {
- /delete-property/mmc-hs200-1_8v;
-};
-
&gpio_keys {
pinctrl-0 = <&pwr_key_l &ap_lid_int_l &volum_down_l &volum_up_l>;
diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
index c706adf..440d678 100644
--- a/arch/arm/boot/dts/rk3288.dtsi
+++ b/arch/arm/boot/dts/rk3288.dtsi
@@ -227,6 +227,7 @@
<GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
<GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
clock-frequency = <24000000>;
+ arm,no-tick-in-suspend;
};
timer: timer@ff810000 {
diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index e1a949b..774a3e5 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -1472,6 +1472,8 @@ static __init void da850_evm_init(void)
if (ret)
pr_warn("%s: dsp/rproc registration failed: %d\n",
__func__, ret);
+
+ regulator_has_full_constraints();
}
#ifdef CONFIG_SERIAL_8250_CONSOLE
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index 1fd3619..3c42bf9 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -685,6 +685,9 @@ static struct platform_device da8xx_lcdc_device = {
.id = 0,
.num_resources = ARRAY_SIZE(da8xx_lcdc_resources),
.resource = da8xx_lcdc_resources,
+ .dev = {
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ }
};
int __init da8xx_register_lcdc(struct da8xx_lcdc_platform_data *pdata)
diff --git a/arch/arm/mach-omap2/prm3xxx.c b/arch/arm/mach-omap2/prm3xxx.c
index 05858f9..dfa65fc 100644
--- a/arch/arm/mach-omap2/prm3xxx.c
+++ b/arch/arm/mach-omap2/prm3xxx.c
@@ -433,7 +433,7 @@ static void omap3_prm_reconfigure_io_chain(void)
* registers, and omap3xxx_prm_reconfigure_io_chain() must be called.
* No return value.
*/
-static void __init omap3xxx_prm_enable_io_wakeup(void)
+static void omap3xxx_prm_enable_io_wakeup(void)
{
if (prm_features & PRM_HAS_IO_WAKEUP)
omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD,
diff --git a/arch/arm/mach-rpc/dma.c b/arch/arm/mach-rpc/dma.c
index fb48f31..c4c9666 100644
--- a/arch/arm/mach-rpc/dma.c
+++ b/arch/arm/mach-rpc/dma.c
@@ -131,7 +131,7 @@ static irqreturn_t iomd_dma_handle(int irq, void *dev_id)
} while (1);
idma->state = ~DMA_ST_AB;
- disable_irq(irq);
+ disable_irq_nosync(irq);
return IRQ_HANDLED;
}
@@ -174,6 +174,9 @@ static void iomd_enable_dma(unsigned int chan, dma_t *dma)
DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
+ idma->dma_addr = idma->dma.sg->dma_address;
+ idma->dma_len = idma->dma.sg->length;
+
iomd_writeb(DMA_CR_C, dma_base + CR);
idma->state = DMA_ST_AB;
}
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index dbee061..bf0109c 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -253,10 +253,8 @@
def_bool y
config ZONE_DMA32
- bool "Enable or Disable Zone DMA"
+ bool "Support DMA32 zone" if EXPERT
default y
- help
- This option is used to enable or disable the DMA zone.
config HAVE_GENERIC_GUP
def_bool y
diff --git a/arch/arm64/boot/Makefile b/arch/arm64/boot/Makefile
index abc6b05..ee0625d 100644
--- a/arch/arm64/boot/Makefile
+++ b/arch/arm64/boot/Makefile
@@ -29,14 +29,15 @@
DTB_OBJS := $(shell find $(obj)/dts/ -name \*.dtb)
# Add RTIC DTB to the DTB list if RTIC MPGen is enabled
+# Note, we keep this for compatibility with
+# BUILD_ARM64_APPENDED_DTB_IMAGE targets.
+# The rtic_mp.dts would be generated with the vmlinux if
+# MPGen enabled (RTIC_MPGEN defined).
ifdef RTIC_MPGEN
DTB_OBJS += rtic_mp.dtb
endif
rtic_mp.dtb: vmlinux FORCE
- $(RTIC_MPGEN) --objcopy="${OBJCOPY}" --objdump="${OBJDUMP}" \
- --binpath="" --vmlinux="vmlinux" --config=${KCONFIG_CONFIG} \
- --cc="${CC} ${KBUILD_AFLAGS}" --dts=rtic_mp.dts && \
$(DTC) -O dtb -o rtic_mp.dtb -b 0 $(DTC_FLAGS) rtic_mp.dts
$(obj)/Image: vmlinux FORCE
diff --git a/arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi b/arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi
index 212e663..7398ae8 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra210-p2180.dtsi
@@ -330,7 +330,8 @@
regulator-max-microvolt = <1320000>;
enable-gpios = <&pmic 6 GPIO_ACTIVE_HIGH>;
regulator-ramp-delay = <80>;
- regulator-enable-ramp-delay = <1000>;
+ regulator-enable-ramp-delay = <2000>;
+ regulator-settling-time-us = <160>;
};
};
};
diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
index 3be920e..6597c08 100644
--- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi
@@ -1119,7 +1119,7 @@
compatible = "nvidia,tegra210-agic";
#interrupt-cells = <3>;
interrupt-controller;
- reg = <0x702f9000 0x2000>,
+ reg = <0x702f9000 0x1000>,
<0x702fa000 0x2000>;
interrupts = <GIC_SPI 102 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
clocks = <&tegra_car TEGRA210_CLK_APE>;
diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index df7e62d..cea44a7 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -1643,11 +1643,11 @@
reg = <0x0 0xff914000 0x0 0x100>, <0x0 0xff915000 0x0 0x100>;
interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH 0>;
interrupt-names = "isp0_mmu";
- clocks = <&cru ACLK_ISP0_NOC>, <&cru HCLK_ISP0_NOC>;
+ clocks = <&cru ACLK_ISP0_WRAPPER>, <&cru HCLK_ISP0_WRAPPER>;
clock-names = "aclk", "iface";
#iommu-cells = <0>;
+ power-domains = <&power RK3399_PD_ISP0>;
rockchip,disable-mmu-reset;
- status = "disabled";
};
isp1_mmu: iommu@ff924000 {
@@ -1655,11 +1655,11 @@
reg = <0x0 0xff924000 0x0 0x100>, <0x0 0xff925000 0x0 0x100>;
interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH 0>;
interrupt-names = "isp1_mmu";
- clocks = <&cru ACLK_ISP1_NOC>, <&cru HCLK_ISP1_NOC>;
+ clocks = <&cru ACLK_ISP1_WRAPPER>, <&cru HCLK_ISP1_WRAPPER>;
clock-names = "aclk", "iface";
#iommu-cells = <0>;
+ power-domains = <&power RK3399_PD_ISP1>;
rockchip,disable-mmu-reset;
- status = "disabled";
};
hdmi_sound: hdmi-sound {
diff --git a/arch/arm64/configs/vendor/bengal_defconfig b/arch/arm64/configs/vendor/bengal_defconfig
index 58f039b..91cff19 100644
--- a/arch/arm64/configs/vendor/bengal_defconfig
+++ b/arch/arm64/configs/vendor/bengal_defconfig
@@ -411,6 +411,7 @@
CONFIG_RNDIS_IPA=y
CONFIG_IPA_UT=y
CONFIG_QCOM_GENI_SE=y
+CONFIG_SM_GCC_BENGAL=y
CONFIG_HWSPINLOCK=y
CONFIG_HWSPINLOCK_QCOM=y
CONFIG_MAILBOX=y
diff --git a/arch/arm64/configs/vendor/kona-perf_defconfig b/arch/arm64/configs/vendor/kona-perf_defconfig
index b8b8527..c2279be 100644
--- a/arch/arm64/configs/vendor/kona-perf_defconfig
+++ b/arch/arm64/configs/vendor/kona-perf_defconfig
@@ -106,6 +106,7 @@
CONFIG_MEMORY_HOTPLUG_MOVABLE_NODE=y
CONFIG_MEMORY_HOTREMOVE=y
CONFIG_CMA=y
+CONFIG_CMA_DEBUGFS=y
CONFIG_CMA_AREAS=16
CONFIG_ZSMALLOC=y
CONFIG_BALANCE_ANON_FILE_RECLAIM=y
@@ -399,6 +400,7 @@
CONFIG_REGULATOR_STUB=y
CONFIG_MEDIA_SUPPORT=y
CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
CONFIG_MEDIA_RADIO_SUPPORT=y
CONFIG_MEDIA_CONTROLLER=y
CONFIG_VIDEO_V4L2_SUBDEV_API=y
@@ -410,6 +412,10 @@
CONFIG_MSM_CVP_V4L2=y
CONFIG_MSM_NPU=y
CONFIG_MSM_GLOBAL_SYNX=y
+CONFIG_DVB_MPQ=m
+CONFIG_DVB_MPQ_DEMUX=m
+CONFIG_DVB_MPQ_TSPP1=y
+CONFIG_TSPP=m
CONFIG_I2C_RTC6226_QCA=y
CONFIG_DRM=y
# CONFIG_DRM_MSM is not set
diff --git a/arch/arm64/configs/vendor/kona_defconfig b/arch/arm64/configs/vendor/kona_defconfig
index f31319e..ef7e81b5 100644
--- a/arch/arm64/configs/vendor/kona_defconfig
+++ b/arch/arm64/configs/vendor/kona_defconfig
@@ -113,6 +113,7 @@
CONFIG_CMA=y
CONFIG_CMA_DEBUG=y
CONFIG_CMA_DEBUGFS=y
+CONFIG_CMA_ALLOW_WRITE_DEBUGFS=y
CONFIG_CMA_AREAS=16
CONFIG_ZSMALLOC=y
CONFIG_BALANCE_ANON_FILE_RECLAIM=y
@@ -412,6 +413,7 @@
CONFIG_REGULATOR_STUB=y
CONFIG_MEDIA_SUPPORT=y
CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
CONFIG_MEDIA_RADIO_SUPPORT=y
CONFIG_MEDIA_CONTROLLER=y
CONFIG_VIDEO_V4L2_SUBDEV_API=y
@@ -423,6 +425,10 @@
CONFIG_MSM_CVP_V4L2=y
CONFIG_MSM_NPU=y
CONFIG_MSM_GLOBAL_SYNX=y
+CONFIG_DVB_MPQ=m
+CONFIG_DVB_MPQ_DEMUX=m
+CONFIG_DVB_MPQ_TSPP1=y
+CONFIG_TSPP=m
CONFIG_I2C_RTC6226_QCA=y
CONFIG_DRM=y
# CONFIG_DRM_MSM is not set
@@ -560,6 +566,7 @@
CONFIG_RPMSG_QCOM_GLINK_SPSS=y
CONFIG_QCOM_COMMAND_DB=y
CONFIG_QCOM_MEM_OFFLINE=y
+CONFIG_BUG_ON_HW_MEM_ONLINE_FAIL=y
CONFIG_OVERRIDE_MEMORY_LIMIT=y
CONFIG_QCOM_CPUSS_DUMP=y
CONFIG_QCOM_RUN_QUEUE_STATS=y
diff --git a/arch/arm64/configs/vendor/lito-perf_defconfig b/arch/arm64/configs/vendor/lito-perf_defconfig
index b745cb6..5e47b38 100644
--- a/arch/arm64/configs/vendor/lito-perf_defconfig
+++ b/arch/arm64/configs/vendor/lito-perf_defconfig
@@ -63,7 +63,6 @@
# CONFIG_EFI is not set
CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y
CONFIG_COMPAT=y
-CONFIG_PM_AUTOSLEEP=y
CONFIG_PM_WAKELOCKS=y
CONFIG_PM_WAKELOCKS_LIMIT=0
# CONFIG_PM_WAKELOCKS_GC is not set
@@ -309,6 +308,7 @@
CONFIG_PPPOL2TP=y
CONFIG_PPP_ASYNC=y
CONFIG_PPP_SYNC_TTY=y
+CONFIG_USB_RTL8152=y
CONFIG_WCNSS_MEM_PRE_ALLOC=y
CONFIG_CLD_LL_CORE=y
CONFIG_CNSS_GENL=y
diff --git a/arch/arm64/configs/vendor/lito_defconfig b/arch/arm64/configs/vendor/lito_defconfig
index a4302f6..ffb5530 100644
--- a/arch/arm64/configs/vendor/lito_defconfig
+++ b/arch/arm64/configs/vendor/lito_defconfig
@@ -63,7 +63,6 @@
CONFIG_RANDOMIZE_BASE=y
CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y
CONFIG_COMPAT=y
-CONFIG_PM_AUTOSLEEP=y
CONFIG_PM_WAKELOCKS=y
CONFIG_PM_WAKELOCKS_LIMIT=0
# CONFIG_PM_WAKELOCKS_GC is not set
@@ -316,6 +315,7 @@
CONFIG_PPPOL2TP=y
CONFIG_PPP_ASYNC=y
CONFIG_PPP_SYNC_TTY=y
+CONFIG_USB_RTL8152=y
CONFIG_WCNSS_MEM_PRE_ALLOC=y
CONFIG_CLD_LL_CORE=y
CONFIG_CNSS_GENL=y
diff --git a/arch/arm64/crypto/sha1-ce-glue.c b/arch/arm64/crypto/sha1-ce-glue.c
index c3d572a..c320030 100644
--- a/arch/arm64/crypto/sha1-ce-glue.c
+++ b/arch/arm64/crypto/sha1-ce-glue.c
@@ -62,7 +62,7 @@ static int sha1_ce_finup(struct shash_desc *desc, const u8 *data,
unsigned int len, u8 *out)
{
struct sha1_ce_state *sctx = shash_desc_ctx(desc);
- bool finalize = !sctx->sst.count && !(len % SHA1_BLOCK_SIZE);
+ bool finalize = !sctx->sst.count && !(len % SHA1_BLOCK_SIZE) && len;
if (!may_use_simd())
return crypto_sha1_finup(desc, data, len, out);
diff --git a/arch/arm64/crypto/sha2-ce-glue.c b/arch/arm64/crypto/sha2-ce-glue.c
index db37282..ddc56fa 100644
--- a/arch/arm64/crypto/sha2-ce-glue.c
+++ b/arch/arm64/crypto/sha2-ce-glue.c
@@ -67,7 +67,7 @@ static int sha256_ce_finup(struct shash_desc *desc, const u8 *data,
unsigned int len, u8 *out)
{
struct sha256_ce_state *sctx = shash_desc_ctx(desc);
- bool finalize = !sctx->sst.count && !(len % SHA256_BLOCK_SIZE);
+ bool finalize = !sctx->sst.count && !(len % SHA256_BLOCK_SIZE) && len;
if (!may_use_simd()) {
if (len)
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index 2870259..50d3ac6 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -124,7 +124,11 @@
* RAS Error Synchronization barrier
*/
.macro esb
+#ifdef CONFIG_ARM64_RAS_EXTN
hint #16
+#else
+ nop
+#endif
.endm
/*
diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h
index 1a037b9..cee28a0 100644
--- a/arch/arm64/include/asm/compat.h
+++ b/arch/arm64/include/asm/compat.h
@@ -159,6 +159,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr)
}
#define compat_user_stack_pointer() (user_stack_pointer(task_pt_regs(current)))
+#define COMPAT_MINSIGSTKSZ 2048
static inline void __user *arch_compat_alloc_user_space(long len)
{
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index 1717ba1..510f687 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -45,9 +45,10 @@
*/
enum ftr_type {
- FTR_EXACT, /* Use a predefined safe value */
- FTR_LOWER_SAFE, /* Smaller value is safe */
- FTR_HIGHER_SAFE,/* Bigger value is safe */
+ FTR_EXACT, /* Use a predefined safe value */
+ FTR_LOWER_SAFE, /* Smaller value is safe */
+ FTR_HIGHER_SAFE, /* Bigger value is safe */
+ FTR_HIGHER_OR_ZERO_SAFE, /* Bigger value is safe, but 0 is biggest */
};
#define FTR_STRICT true /* SANITY check strict matching required */
diff --git a/arch/arm64/include/asm/dma-iommu.h b/arch/arm64/include/asm/dma-iommu.h
index 4cb442c..80397db 100644
--- a/arch/arm64/include/asm/dma-iommu.h
+++ b/arch/arm64/include/asm/dma-iommu.h
@@ -28,42 +28,8 @@ struct dma_iommu_mapping {
};
#ifdef CONFIG_ARM64_DMA_USE_IOMMU
-
-struct dma_iommu_mapping *
-__depr_arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base,
- size_t size);
-
-void __depr_arm_iommu_release_mapping(struct dma_iommu_mapping *mapping);
-
-int __depr_arm_iommu_attach_device(struct device *dev,
- struct dma_iommu_mapping *mapping);
-void __depr_arm_iommu_detach_device(struct device *dev);
-
void arm_iommu_put_dma_cookie(struct iommu_domain *domain);
#else /* !CONFIG_ARM64_DMA_USE_IOMMU */
-
-static inline struct dma_iommu_mapping *
-__depr_arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base,
- size_t size)
-{
- return NULL;
-}
-
-static inline void
-__depr_arm_iommu_release_mapping(struct dma_iommu_mapping *mapping)
-{
-}
-
-static inline int __depr_arm_iommu_attach_device(struct device *dev,
- struct dma_iommu_mapping *mapping)
-{
- return -ENODEV;
-}
-
-static inline void __depr_arm_iommu_detach_device(struct device *dev)
-{
-}
-
static inline void arm_iommu_put_dma_cookie(struct iommu_domain *domain) {}
#endif /* CONFIG_ARM64_DMA_USE_IOMMU */
diff --git a/arch/arm64/include/asm/syscall_wrapper.h b/arch/arm64/include/asm/syscall_wrapper.h
index 507d0ee..e9330f8 100644
--- a/arch/arm64/include/asm/syscall_wrapper.h
+++ b/arch/arm64/include/asm/syscall_wrapper.h
@@ -8,6 +8,8 @@
#ifndef __ASM_SYSCALL_WRAPPER_H
#define __ASM_SYSCALL_WRAPPER_H
+struct pt_regs;
+
#define SC_ARM64_REGS_TO_ARGS(x, ...) \
__MAP(x,__SC_ARGS \
,,regs->regs[0],,regs->regs[1],,regs->regs[2] \
@@ -35,8 +37,11 @@
ALLOW_ERROR_INJECTION(__arm64_compat_sys_##sname, ERRNO); \
asmlinkage long __arm64_compat_sys_##sname(const struct pt_regs *__unused)
-#define COND_SYSCALL_COMPAT(name) \
- cond_syscall(__arm64_compat_sys_##name);
+#define COND_SYSCALL_COMPAT(name) \
+ asmlinkage __weak long __arm64_compat_sys_##name(const struct pt_regs *__unused)\
+ { \
+ return sys_ni_syscall(); \
+ }
#define COMPAT_SYS_NI(name) \
SYSCALL_ALIAS(__arm64_compat_sys_##name, sys_ni_posix_timers);
@@ -70,7 +75,11 @@
#endif
#ifndef COND_SYSCALL
-#define COND_SYSCALL(name) cond_syscall(__arm64_sys_##name)
+#define COND_SYSCALL(name) \
+ asmlinkage __weak long __arm64_sys_##name(const struct pt_regs *regs) \
+ { \
+ return sys_ni_syscall(); \
+ }
#endif
#ifndef SYS_NI
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index ed46dc1..970f15c 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -154,10 +154,14 @@ static int __init acpi_fadt_sanity_check(void)
*/
if (table->revision < 5 ||
(table->revision == 5 && fadt->minor_revision < 1)) {
- pr_err("Unsupported FADT revision %d.%d, should be 5.1+\n",
+ pr_err(FW_BUG "Unsupported FADT revision %d.%d, should be 5.1+\n",
table->revision, fadt->minor_revision);
- ret = -EINVAL;
- goto out;
+
+ if (!fadt->arm_boot_flags) {
+ ret = -EINVAL;
+ goto out;
+ }
+ pr_err("FADT has ARM boot flags set, assuming 5.1\n");
}
if (!(fadt->flags & ACPI_FADT_HW_REDUCED)) {
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 8181685..e1fcfca 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -211,8 +211,8 @@ static const struct arm64_ftr_bits ftr_ctr[] = {
ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, 31, 1, 1), /* RES1 */
ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, CTR_DIC_SHIFT, 1, 1),
ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, CTR_IDC_SHIFT, 1, 1),
- ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_HIGHER_SAFE, CTR_CWG_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_HIGHER_SAFE, CTR_ERG_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_HIGHER_OR_ZERO_SAFE, CTR_CWG_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_HIGHER_OR_ZERO_SAFE, CTR_ERG_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, CTR_DMINLINE_SHIFT, 4, 1),
/*
* Linux can handle differing I-cache policies. Userspace JITs will
@@ -454,6 +454,10 @@ static s64 arm64_ftr_safe_value(const struct arm64_ftr_bits *ftrp, s64 new,
case FTR_LOWER_SAFE:
ret = new < cur ? new : cur;
break;
+ case FTR_HIGHER_OR_ZERO_SAFE:
+ if (!cur || !new)
+ break;
+ /* Fallthrough */
case FTR_HIGHER_SAFE:
ret = new > cur ? new : cur;
break;
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index f0a0464..adc166c 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -835,7 +835,7 @@
mov x1, x25
mov x2, sp
bl do_debug_exception
- enable_daif
+ enable_da_f
ct_user_exit
b ret_to_user
el0_inv:
@@ -887,7 +887,7 @@
enable_dbg
mov x0, sp
bl do_serror
- enable_daif
+ enable_da_f
ct_user_exit
b ret_to_user
ENDPROC(el0_error)
diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
index 397d083..6ae2236 100644
--- a/arch/arm64/kernel/hw_breakpoint.c
+++ b/arch/arm64/kernel/hw_breakpoint.c
@@ -547,13 +547,14 @@ int hw_breakpoint_arch_parse(struct perf_event *bp,
/* Aligned */
break;
case 1:
- /* Allow single byte watchpoint. */
- if (hw->ctrl.len == ARM_BREAKPOINT_LEN_1)
- break;
case 2:
/* Allow halfword watchpoints and breakpoints. */
if (hw->ctrl.len == ARM_BREAKPOINT_LEN_2)
break;
+ case 3:
+ /* Allow single byte watchpoint. */
+ if (hw->ctrl.len == ARM_BREAKPOINT_LEN_1)
+ break;
default:
return -EINVAL;
}
diff --git a/arch/arm64/kernel/image.h b/arch/arm64/kernel/image.h
index 8da289d..eff6a56 100644
--- a/arch/arm64/kernel/image.h
+++ b/arch/arm64/kernel/image.h
@@ -73,7 +73,11 @@
#ifdef CONFIG_EFI
-__efistub_stext_offset = stext - _text;
+/*
+ * Use ABSOLUTE() to avoid ld.lld treating this as a relative symbol:
+ * https://github.com/ClangBuiltLinux/linux/issues/561
+ */
+__efistub_stext_offset = ABSOLUTE(stext - _text);
/*
* The EFI stub has its own symbol namespace prefixed by __efistub_, to
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index d12667d..430ea0e 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -1151,179 +1151,6 @@ static void arm_iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 size)
set_dma_ops(dev, mapping.ops);
}
-/**
- * DEPRECATED
- * arm_iommu_create_mapping
- * @bus: pointer to the bus holding the client device (for IOMMU calls)
- * @base: start address of the valid IO address space
- * @size: maximum size of the valid IO address space
- *
- * Creates a mapping structure which holds information about used/unused
- * IO address ranges, which is required to perform memory allocation and
- * mapping with IOMMU aware functions.
- *
- * Clients may use iommu_domain_set_attr() to set additional flags prior
- * to calling arm_iommu_attach_device() to complete initialization.
- */
-struct dma_iommu_mapping *
-__depr_arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base,
- size_t size)
-{
- unsigned int bits = size >> PAGE_SHIFT;
- struct dma_iommu_mapping *mapping;
-
- if (!bits)
- return ERR_PTR(-EINVAL);
-
- mapping = kzalloc(sizeof(struct dma_iommu_mapping), GFP_KERNEL);
- if (!mapping)
- return ERR_PTR(-ENOMEM);
-
- mapping->base = base;
- mapping->bits = bits;
-
- mapping->domain = iommu_domain_alloc(bus);
- if (!mapping->domain)
- goto err_domain_alloc;
-
- mapping->init = false;
- return mapping;
-
-err_domain_alloc:
- kfree(mapping);
- return ERR_PTR(-ENOMEM);
-}
-EXPORT_SYMBOL(__depr_arm_iommu_create_mapping);
-
-/*
- * DEPRECATED
- * arm_iommu_release_mapping
- * @mapping: allocted via arm_iommu_create_mapping()
- *
- * Frees all resources associated with the iommu mapping.
- * The device associated with this mapping must be in the 'detached' state
- */
-void __depr_arm_iommu_release_mapping(struct dma_iommu_mapping *mapping)
-{
- if (!mapping)
- return;
-
- if (mapping->domain)
- iommu_domain_free(mapping->domain);
-
- kfree(mapping);
-}
-EXPORT_SYMBOL(__depr_arm_iommu_release_mapping);
-
-/**
- * DEPRECATED
- * arm_iommu_attach_device
- * @dev: valid struct device pointer
- * @mapping: io address space mapping structure (returned from
- * arm_iommu_create_mapping)
- *
- * Attaches specified io address space mapping to the provided device,
- * this replaces the dma operations (dma_map_ops pointer) with the
- * IOMMU aware version.
- *
- * Only configures dma_ops for a single device in the iommu_group.
- */
-int __depr_arm_iommu_attach_device(struct device *dev,
- struct dma_iommu_mapping *mapping)
-{
- int err;
- struct iommu_domain *domain;
- struct iommu_group *group;
-
- if (!dev || !mapping) {
- pr_err("%s: Error input is NULL\n", __func__);
- return -EINVAL;
- }
-
- group = dev->iommu_group;
- if (!group) {
- dev_err(dev, "No iommu associated with device\n");
- return -EINVAL;
- }
-
- domain = iommu_get_domain_for_dev(dev);
- if (domain) {
- int dynamic = 0;
-
- iommu_domain_get_attr(domain, DOMAIN_ATTR_DYNAMIC, &dynamic);
-
- if ((domain->type == IOMMU_DOMAIN_DMA) && dynamic) {
- dev_warn(dev, "Deprecated API %s in use! Continuing anyway\n",
- __func__);
- } else {
- dev_err(dev, "Device already attached to other iommu_domain\n");
- return -EINVAL;
- }
- }
-
- err = iommu_attach_group(mapping->domain, group);
- if (err) {
- dev_err(dev, "iommu_attach_group failed\n");
- return err;
- }
-
- err = arm_iommu_get_dma_cookie(dev, mapping);
- if (err) {
- dev_err(dev, "arm_iommu_get_dma_cookie failed\n");
- iommu_detach_group(domain, group);
- return err;
- }
-
- dev->archdata.mapping = mapping;
- set_dma_ops(dev, mapping->ops);
-
- pr_debug("Attached IOMMU controller to %s device.\n", dev_name(dev));
- return 0;
-}
-EXPORT_SYMBOL(__depr_arm_iommu_attach_device);
-
-/**
- * DEPRECATED
- * arm_iommu_detach_device
- * @dev: valid struct device pointer
- *
- * Detaches the provided device from a previously attached map.
- * This voids the dma operations (dma_map_ops pointer)
- */
-void __depr_arm_iommu_detach_device(struct device *dev)
-{
- struct iommu_domain *domain;
- int s1_bypass = 0;
-
- if (!dev->iommu_group) {
- dev_err(dev, "No iommu associated with device\n");
- return;
- }
-
- domain = iommu_get_domain_for_dev(dev);
- if (!domain) {
- dev_warn(dev, "Not attached\n");
- return;
- }
-
- iommu_domain_get_attr(domain, DOMAIN_ATTR_S1_BYPASS, &s1_bypass);
-
- /*
- * ION defers dma_unmap calls. Ensure they have all completed prior to
- * setting dma_ops to NULL.
- */
- if (msm_dma_unmap_all_for_dev(dev))
- dev_warn(dev, "IOMMU detach with outstanding mappings\n");
-
- iommu_detach_group(domain, dev->iommu_group);
- dev->archdata.mapping = NULL;
- if (!s1_bypass)
- set_dma_ops(dev, NULL);
-
- pr_debug("Detached IOMMU controller from %s device.\n", dev_name(dev));
-}
-EXPORT_SYMBOL(__depr_arm_iommu_detach_device);
-
#else /*!CONFIG_ARM64_DMA_USE_IOMMU */
static void arm_iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 size)
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 7bcc232..89c87a6 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -236,8 +236,9 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
{
unsigned long max_zone_pfns[MAX_NR_ZONES] = {0};
- if (IS_ENABLED(CONFIG_ZONE_DMA32))
- max_zone_pfns[ZONE_DMA32] = PFN_DOWN(max_zone_dma_phys());
+#ifdef CONFIG_ZONE_DMA32
+ max_zone_pfns[ZONE_DMA32] = PFN_DOWN(max_zone_dma_phys());
+#endif
max_zone_pfns[ZONE_NORMAL] = max;
free_area_init_nodes(max_zone_pfns);
diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile
index 3c453a1..172801e 100644
--- a/arch/mips/boot/compressed/Makefile
+++ b/arch/mips/boot/compressed/Makefile
@@ -78,6 +78,8 @@
$(obj)/piggy.o: $(obj)/dummy.o $(obj)/vmlinux.bin.z FORCE
$(call if_changed,objcopy)
+HOSTCFLAGS_calc_vmlinuz_load_addr.o += $(LINUXINCLUDE)
+
# Calculate the load address of the compressed kernel image
hostprogs-y := calc_vmlinuz_load_addr
diff --git a/arch/mips/boot/compressed/calc_vmlinuz_load_addr.c b/arch/mips/boot/compressed/calc_vmlinuz_load_addr.c
index 542c3ed..d14f75e 100644
--- a/arch/mips/boot/compressed/calc_vmlinuz_load_addr.c
+++ b/arch/mips/boot/compressed/calc_vmlinuz_load_addr.c
@@ -13,7 +13,7 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
-#include "../../../../include/linux/sizes.h"
+#include <linux/sizes.h>
int main(int argc, char *argv[])
{
diff --git a/arch/mips/include/asm/mach-ath79/ar933x_uart.h b/arch/mips/include/asm/mach-ath79/ar933x_uart.h
index c2917b3..bba2c88 100644
--- a/arch/mips/include/asm/mach-ath79/ar933x_uart.h
+++ b/arch/mips/include/asm/mach-ath79/ar933x_uart.h
@@ -27,8 +27,8 @@
#define AR933X_UART_CS_PARITY_S 0
#define AR933X_UART_CS_PARITY_M 0x3
#define AR933X_UART_CS_PARITY_NONE 0
-#define AR933X_UART_CS_PARITY_ODD 1
-#define AR933X_UART_CS_PARITY_EVEN 2
+#define AR933X_UART_CS_PARITY_ODD 2
+#define AR933X_UART_CS_PARITY_EVEN 3
#define AR933X_UART_CS_IF_MODE_S 2
#define AR933X_UART_CS_IF_MODE_M 0x3
#define AR933X_UART_CS_IF_MODE_NONE 0
diff --git a/arch/mips/include/uapi/asm/sgidefs.h b/arch/mips/include/uapi/asm/sgidefs.h
index 26143e3..69c3de9 100644
--- a/arch/mips/include/uapi/asm/sgidefs.h
+++ b/arch/mips/include/uapi/asm/sgidefs.h
@@ -12,14 +12,6 @@
#define __ASM_SGIDEFS_H
/*
- * Using a Linux compiler for building Linux seems logic but not to
- * everybody.
- */
-#ifndef __linux__
-#error Use a Linux compiler or give up.
-#endif
-
-/*
* Definitions for the ISA levels
*
* With the introduction of MIPS32 / MIPS64 instruction sets definitions
diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c
index 705593d..05c60fa 100644
--- a/arch/mips/jz4740/board-qi_lb60.c
+++ b/arch/mips/jz4740/board-qi_lb60.c
@@ -471,27 +471,27 @@ static unsigned long pin_cfg_bias_disable[] = {
static struct pinctrl_map pin_map[] __initdata = {
/* NAND pin configuration */
PIN_MAP_MUX_GROUP_DEFAULT("jz4740-nand",
- "10010000.jz4740-pinctrl", "nand", "nand-cs1"),
+ "10010000.pin-controller", "nand-cs1", "nand"),
/* fbdev pin configuration */
PIN_MAP_MUX_GROUP("jz4740-fb", PINCTRL_STATE_DEFAULT,
- "10010000.jz4740-pinctrl", "lcd", "lcd-8bit"),
+ "10010000.pin-controller", "lcd-8bit", "lcd"),
PIN_MAP_MUX_GROUP("jz4740-fb", PINCTRL_STATE_SLEEP,
- "10010000.jz4740-pinctrl", "lcd", "lcd-no-pins"),
+ "10010000.pin-controller", "lcd-no-pins", "lcd"),
/* MMC pin configuration */
PIN_MAP_MUX_GROUP_DEFAULT("jz4740-mmc.0",
- "10010000.jz4740-pinctrl", "mmc", "mmc-1bit"),
+ "10010000.pin-controller", "mmc-1bit", "mmc"),
PIN_MAP_MUX_GROUP_DEFAULT("jz4740-mmc.0",
- "10010000.jz4740-pinctrl", "mmc", "mmc-4bit"),
+ "10010000.pin-controller", "mmc-4bit", "mmc"),
PIN_MAP_CONFIGS_PIN_DEFAULT("jz4740-mmc.0",
- "10010000.jz4740-pinctrl", "PD0", pin_cfg_bias_disable),
+ "10010000.pin-controller", "PD0", pin_cfg_bias_disable),
PIN_MAP_CONFIGS_PIN_DEFAULT("jz4740-mmc.0",
- "10010000.jz4740-pinctrl", "PD2", pin_cfg_bias_disable),
+ "10010000.pin-controller", "PD2", pin_cfg_bias_disable),
/* PWM pin configuration */
PIN_MAP_MUX_GROUP_DEFAULT("jz4740-pwm",
- "10010000.jz4740-pinctrl", "pwm4", "pwm4"),
+ "10010000.pin-controller", "pwm4", "pwm4"),
};
diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c
index c4ef1c3..37caead 100644
--- a/arch/mips/lantiq/irq.c
+++ b/arch/mips/lantiq/irq.c
@@ -156,8 +156,9 @@ static int ltq_eiu_settype(struct irq_data *d, unsigned int type)
if (edge)
irq_set_handler(d->hwirq, handle_edge_irq);
- ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) |
- (val << (i * 4)), LTQ_EIU_EXIN_C);
+ ltq_eiu_w32((ltq_eiu_r32(LTQ_EIU_EXIN_C) &
+ (~(7 << (i * 4)))) | (val << (i * 4)),
+ LTQ_EIU_EXIN_C);
}
}
diff --git a/arch/parisc/boot/compressed/vmlinux.lds.S b/arch/parisc/boot/compressed/vmlinux.lds.S
index 4ebd4e6..41ebe97 100644
--- a/arch/parisc/boot/compressed/vmlinux.lds.S
+++ b/arch/parisc/boot/compressed/vmlinux.lds.S
@@ -42,8 +42,8 @@
#endif
_startcode_end = .;
- /* bootloader code and data starts behind area of extracted kernel */
- . = (SZ_end - SZparisc_kernel_start + KERNEL_BINARY_TEXT_START);
+ /* bootloader code and data starts at least behind area of extracted kernel */
+ . = MAX(ABSOLUTE(.), (SZ_end - SZparisc_kernel_start + KERNEL_BINARY_TEXT_START));
/* align on next page boundary */
. = ALIGN(4096);
diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c
index 0964c23..de2998c 100644
--- a/arch/parisc/kernel/ptrace.c
+++ b/arch/parisc/kernel/ptrace.c
@@ -167,6 +167,9 @@ long arch_ptrace(struct task_struct *child, long request,
if ((addr & (sizeof(unsigned long)-1)) ||
addr >= sizeof(struct pt_regs))
break;
+ if (addr == PT_IAOQ0 || addr == PT_IAOQ1) {
+ data |= 3; /* ensure userspace privilege */
+ }
if ((addr >= PT_GR1 && addr <= PT_GR31) ||
addr == PT_IAOQ0 || addr == PT_IAOQ1 ||
(addr >= PT_FR0 && addr <= PT_FR31 + 4) ||
@@ -228,16 +231,18 @@ long arch_ptrace(struct task_struct *child, long request,
static compat_ulong_t translate_usr_offset(compat_ulong_t offset)
{
- if (offset < 0)
- return sizeof(struct pt_regs);
- else if (offset <= 32*4) /* gr[0..31] */
- return offset * 2 + 4;
- else if (offset <= 32*4+32*8) /* gr[0..31] + fr[0..31] */
- return offset + 32*4;
- else if (offset < sizeof(struct pt_regs)/2 + 32*4)
- return offset * 2 + 4 - 32*8;
+ compat_ulong_t pos;
+
+ if (offset < 32*4) /* gr[0..31] */
+ pos = offset * 2 + 4;
+ else if (offset < 32*4+32*8) /* fr[0] ... fr[31] */
+ pos = (offset - 32*4) + PT_FR0;
+ else if (offset < sizeof(struct pt_regs)/2 + 32*4) /* sr[0] ... ipsw */
+ pos = (offset - 32*4 - 32*8) * 2 + PT_SR0 + 4;
else
- return sizeof(struct pt_regs);
+ pos = sizeof(struct pt_regs);
+
+ return pos;
}
long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
@@ -281,9 +286,12 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
addr = translate_usr_offset(addr);
if (addr >= sizeof(struct pt_regs))
break;
+ if (addr == PT_IAOQ0+4 || addr == PT_IAOQ1+4) {
+ data |= 3; /* ensure userspace privilege */
+ }
if (addr >= PT_FR0 && addr <= PT_FR31 + 4) {
/* Special case, fp regs are 64 bits anyway */
- *(__u64 *) ((char *) task_regs(child) + addr) = data;
+ *(__u32 *) ((char *) task_regs(child) + addr) = data;
ret = 0;
}
else if ((addr >= PT_GR1+4 && addr <= PT_GR31+4) ||
@@ -496,7 +504,8 @@ static void set_reg(struct pt_regs *regs, int num, unsigned long val)
return;
case RI(iaoq[0]):
case RI(iaoq[1]):
- regs->iaoq[num - RI(iaoq[0])] = val;
+ /* set 2 lowest bits to ensure userspace privilege: */
+ regs->iaoq[num - RI(iaoq[0])] = val | 3;
return;
case RI(sar): regs->sar = val;
return;
diff --git a/arch/powerpc/boot/xz_config.h b/arch/powerpc/boot/xz_config.h
index e22e5b3..ebfadd3 100644
--- a/arch/powerpc/boot/xz_config.h
+++ b/arch/powerpc/boot/xz_config.h
@@ -20,10 +20,30 @@ static inline uint32_t swab32p(void *p)
#ifdef __LITTLE_ENDIAN__
#define get_le32(p) (*((uint32_t *) (p)))
+#define cpu_to_be32(x) swab32(x)
+static inline u32 be32_to_cpup(const u32 *p)
+{
+ return swab32p((u32 *)p);
+}
#else
#define get_le32(p) swab32p(p)
+#define cpu_to_be32(x) (x)
+static inline u32 be32_to_cpup(const u32 *p)
+{
+ return *p;
+}
#endif
+static inline uint32_t get_unaligned_be32(const void *p)
+{
+ return be32_to_cpup(p);
+}
+
+static inline void put_unaligned_be32(u32 val, void *p)
+{
+ *((u32 *)p) = cpu_to_be32(val);
+}
+
#define memeq(a, b, size) (memcmp(a, b, size) == 0)
#define memzero(buf, size) memset(buf, 0, size)
diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h
index d5a8d7b..b189f7a 100644
--- a/arch/powerpc/include/asm/cacheflush.h
+++ b/arch/powerpc/include/asm/cacheflush.h
@@ -32,9 +32,12 @@
* not expect this type of fault. flush_cache_vmap is not exactly the right
* place to put this, but it seems to work well enough.
*/
-#define flush_cache_vmap(start, end) do { asm volatile("ptesync" ::: "memory"); } while (0)
+static inline void flush_cache_vmap(unsigned long start, unsigned long end)
+{
+ asm volatile("ptesync" ::: "memory");
+}
#else
-#define flush_cache_vmap(start, end) do { } while (0)
+static inline void flush_cache_vmap(unsigned long start, unsigned long end) { }
#endif
#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
index c72767a..fe3c6f3 100644
--- a/arch/powerpc/kernel/eeh.c
+++ b/arch/powerpc/kernel/eeh.c
@@ -360,10 +360,19 @@ static inline unsigned long eeh_token_to_phys(unsigned long token)
ptep = find_init_mm_pte(token, &hugepage_shift);
if (!ptep)
return token;
- WARN_ON(hugepage_shift);
- pa = pte_pfn(*ptep) << PAGE_SHIFT;
- return pa | (token & (PAGE_SIZE-1));
+ pa = pte_pfn(*ptep);
+
+ /* On radix we can do hugepage mappings for io, so handle that */
+ if (hugepage_shift) {
+ pa <<= hugepage_shift;
+ pa |= token & ((1ul << hugepage_shift) - 1);
+ } else {
+ pa <<= PAGE_SHIFT;
+ pa |= token & (PAGE_SIZE - 1);
+ }
+
+ return pa;
}
/*
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 2d8fc8c..06cc778 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -1745,7 +1745,7 @@
addi r3,r1,STACK_FRAME_OVERHEAD
bl do_page_fault
cmpdi r3,0
- beq+ 12f
+ beq+ ret_from_except_lite
bl save_nvgprs
mr r5,r3
addi r3,r1,STACK_FRAME_OVERHEAD
@@ -1760,7 +1760,12 @@
ld r5,_DSISR(r1)
addi r3,r1,STACK_FRAME_OVERHEAD
bl do_break
-12: b ret_from_except_lite
+ /*
+ * do_break() may have changed the NV GPRS while handling a breakpoint.
+ * If so, we need to restore them with their updated values. Don't use
+ * ret_from_except_lite here.
+ */
+ b ret_from_except
#ifdef CONFIG_PPC_BOOK3S_64
diff --git a/arch/powerpc/kernel/pci_of_scan.c b/arch/powerpc/kernel/pci_of_scan.c
index 98f0472..c101b32 100644
--- a/arch/powerpc/kernel/pci_of_scan.c
+++ b/arch/powerpc/kernel/pci_of_scan.c
@@ -45,6 +45,8 @@ unsigned int pci_parse_of_flags(u32 addr0, int bridge)
if (addr0 & 0x02000000) {
flags = IORESOURCE_MEM | PCI_BASE_ADDRESS_SPACE_MEMORY;
flags |= (addr0 >> 22) & PCI_BASE_ADDRESS_MEM_TYPE_64;
+ if (flags & PCI_BASE_ADDRESS_MEM_TYPE_64)
+ flags |= IORESOURCE_MEM_64;
flags |= (addr0 >> 28) & PCI_BASE_ADDRESS_MEM_TYPE_1M;
if (addr0 & 0x40000000)
flags |= IORESOURCE_PREFETCH
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index fd59fef..906b05c 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -1202,6 +1202,9 @@ SYSCALL_DEFINE0(rt_sigreturn)
goto bad;
if (MSR_TM_ACTIVE(msr_hi<<32)) {
+ /* Trying to start TM on non TM system */
+ if (!cpu_has_feature(CPU_FTR_TM))
+ goto bad;
/* We only recheckpoint on return if we're
* transaction.
*/
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index 14b0f5b..b5933d72 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -750,6 +750,11 @@ SYSCALL_DEFINE0(rt_sigreturn)
if (MSR_TM_ACTIVE(msr)) {
/* We recheckpoint on return. */
struct ucontext __user *uc_transact;
+
+ /* Trying to start TM on non TM system */
+ if (!cpu_has_feature(CPU_FTR_TM))
+ goto badframe;
+
if (__get_user(uc_transact, &uc->uc_link))
goto badframe;
if (restore_tm_sigcontexts(current, &uc->uc_mcontext,
diff --git a/arch/powerpc/kernel/swsusp_32.S b/arch/powerpc/kernel/swsusp_32.S
index 7a919e9..cbdf862 100644
--- a/arch/powerpc/kernel/swsusp_32.S
+++ b/arch/powerpc/kernel/swsusp_32.S
@@ -25,11 +25,19 @@
#define SL_IBAT2 0x48
#define SL_DBAT3 0x50
#define SL_IBAT3 0x58
-#define SL_TB 0x60
-#define SL_R2 0x68
-#define SL_CR 0x6c
-#define SL_LR 0x70
-#define SL_R12 0x74 /* r12 to r31 */
+#define SL_DBAT4 0x60
+#define SL_IBAT4 0x68
+#define SL_DBAT5 0x70
+#define SL_IBAT5 0x78
+#define SL_DBAT6 0x80
+#define SL_IBAT6 0x88
+#define SL_DBAT7 0x90
+#define SL_IBAT7 0x98
+#define SL_TB 0xa0
+#define SL_R2 0xa8
+#define SL_CR 0xac
+#define SL_LR 0xb0
+#define SL_R12 0xb4 /* r12 to r31 */
#define SL_SIZE (SL_R12 + 80)
.section .data
@@ -114,6 +122,41 @@
mfibatl r4,3
stw r4,SL_IBAT3+4(r11)
+BEGIN_MMU_FTR_SECTION
+ mfspr r4,SPRN_DBAT4U
+ stw r4,SL_DBAT4(r11)
+ mfspr r4,SPRN_DBAT4L
+ stw r4,SL_DBAT4+4(r11)
+ mfspr r4,SPRN_DBAT5U
+ stw r4,SL_DBAT5(r11)
+ mfspr r4,SPRN_DBAT5L
+ stw r4,SL_DBAT5+4(r11)
+ mfspr r4,SPRN_DBAT6U
+ stw r4,SL_DBAT6(r11)
+ mfspr r4,SPRN_DBAT6L
+ stw r4,SL_DBAT6+4(r11)
+ mfspr r4,SPRN_DBAT7U
+ stw r4,SL_DBAT7(r11)
+ mfspr r4,SPRN_DBAT7L
+ stw r4,SL_DBAT7+4(r11)
+ mfspr r4,SPRN_IBAT4U
+ stw r4,SL_IBAT4(r11)
+ mfspr r4,SPRN_IBAT4L
+ stw r4,SL_IBAT4+4(r11)
+ mfspr r4,SPRN_IBAT5U
+ stw r4,SL_IBAT5(r11)
+ mfspr r4,SPRN_IBAT5L
+ stw r4,SL_IBAT5+4(r11)
+ mfspr r4,SPRN_IBAT6U
+ stw r4,SL_IBAT6(r11)
+ mfspr r4,SPRN_IBAT6L
+ stw r4,SL_IBAT6+4(r11)
+ mfspr r4,SPRN_IBAT7U
+ stw r4,SL_IBAT7(r11)
+ mfspr r4,SPRN_IBAT7L
+ stw r4,SL_IBAT7+4(r11)
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
+
#if 0
/* Backup various CPU config stuffs */
bl __save_cpu_setup
@@ -279,27 +322,41 @@
mtibatu 3,r4
lwz r4,SL_IBAT3+4(r11)
mtibatl 3,r4
-#endif
-
BEGIN_MMU_FTR_SECTION
- li r4,0
+ lwz r4,SL_DBAT4(r11)
mtspr SPRN_DBAT4U,r4
+ lwz r4,SL_DBAT4+4(r11)
mtspr SPRN_DBAT4L,r4
+ lwz r4,SL_DBAT5(r11)
mtspr SPRN_DBAT5U,r4
+ lwz r4,SL_DBAT5+4(r11)
mtspr SPRN_DBAT5L,r4
+ lwz r4,SL_DBAT6(r11)
mtspr SPRN_DBAT6U,r4
+ lwz r4,SL_DBAT6+4(r11)
mtspr SPRN_DBAT6L,r4
+ lwz r4,SL_DBAT7(r11)
mtspr SPRN_DBAT7U,r4
+ lwz r4,SL_DBAT7+4(r11)
mtspr SPRN_DBAT7L,r4
+ lwz r4,SL_IBAT4(r11)
mtspr SPRN_IBAT4U,r4
+ lwz r4,SL_IBAT4+4(r11)
mtspr SPRN_IBAT4L,r4
+ lwz r4,SL_IBAT5(r11)
mtspr SPRN_IBAT5U,r4
+ lwz r4,SL_IBAT5+4(r11)
mtspr SPRN_IBAT5L,r4
+ lwz r4,SL_IBAT6(r11)
mtspr SPRN_IBAT6U,r4
+ lwz r4,SL_IBAT6+4(r11)
mtspr SPRN_IBAT6L,r4
+ lwz r4,SL_IBAT7(r11)
mtspr SPRN_IBAT7U,r4
+ lwz r4,SL_IBAT7+4(r11)
mtspr SPRN_IBAT7L,r4
END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
+#endif
/* Flush all TLBs */
lis r4,0x1000
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index 7296a42..cef0b7e 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -150,6 +150,8 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr, unsigned long sz
} else {
pdshift = PUD_SHIFT;
pu = pud_alloc(mm, pg, addr);
+ if (!pu)
+ return NULL;
if (pshift == PUD_SHIFT)
return (pte_t *)pu;
else if (pshift > PMD_SHIFT) {
@@ -158,6 +160,8 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr, unsigned long sz
} else {
pdshift = PMD_SHIFT;
pm = pmd_alloc(mm, pu, addr);
+ if (!pm)
+ return NULL;
if (pshift == PMD_SHIFT)
/* 16MB hugepage */
return (pte_t *)pm;
@@ -174,12 +178,16 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr, unsigned long sz
} else {
pdshift = PUD_SHIFT;
pu = pud_alloc(mm, pg, addr);
+ if (!pu)
+ return NULL;
if (pshift >= PUD_SHIFT) {
ptl = pud_lockptr(mm, pu);
hpdp = (hugepd_t *)pu;
} else {
pdshift = PMD_SHIFT;
pm = pmd_alloc(mm, pu, addr);
+ if (!pm)
+ return NULL;
ptl = pmd_lockptr(mm, pm);
hpdp = (hugepd_t *)pm;
}
diff --git a/arch/powerpc/platforms/4xx/uic.c b/arch/powerpc/platforms/4xx/uic.c
index 8b4dd0d..9e27cfe 100644
--- a/arch/powerpc/platforms/4xx/uic.c
+++ b/arch/powerpc/platforms/4xx/uic.c
@@ -158,6 +158,7 @@ static int uic_set_irq_type(struct irq_data *d, unsigned int flow_type)
mtdcr(uic->dcrbase + UIC_PR, pr);
mtdcr(uic->dcrbase + UIC_TR, tr);
+ mtdcr(uic->dcrbase + UIC_SR, ~mask);
raw_spin_unlock_irqrestore(&uic->lock, flags);
diff --git a/arch/powerpc/platforms/powermac/sleep.S b/arch/powerpc/platforms/powermac/sleep.S
index f89808b..b0660ef 100644
--- a/arch/powerpc/platforms/powermac/sleep.S
+++ b/arch/powerpc/platforms/powermac/sleep.S
@@ -38,10 +38,18 @@
#define SL_IBAT2 0x48
#define SL_DBAT3 0x50
#define SL_IBAT3 0x58
-#define SL_TB 0x60
-#define SL_R2 0x68
-#define SL_CR 0x6c
-#define SL_R12 0x70 /* r12 to r31 */
+#define SL_DBAT4 0x60
+#define SL_IBAT4 0x68
+#define SL_DBAT5 0x70
+#define SL_IBAT5 0x78
+#define SL_DBAT6 0x80
+#define SL_IBAT6 0x88
+#define SL_DBAT7 0x90
+#define SL_IBAT7 0x98
+#define SL_TB 0xa0
+#define SL_R2 0xa8
+#define SL_CR 0xac
+#define SL_R12 0xb0 /* r12 to r31 */
#define SL_SIZE (SL_R12 + 80)
.section .text
@@ -126,6 +134,41 @@
mfibatl r4,3
stw r4,SL_IBAT3+4(r1)
+BEGIN_MMU_FTR_SECTION
+ mfspr r4,SPRN_DBAT4U
+ stw r4,SL_DBAT4(r1)
+ mfspr r4,SPRN_DBAT4L
+ stw r4,SL_DBAT4+4(r1)
+ mfspr r4,SPRN_DBAT5U
+ stw r4,SL_DBAT5(r1)
+ mfspr r4,SPRN_DBAT5L
+ stw r4,SL_DBAT5+4(r1)
+ mfspr r4,SPRN_DBAT6U
+ stw r4,SL_DBAT6(r1)
+ mfspr r4,SPRN_DBAT6L
+ stw r4,SL_DBAT6+4(r1)
+ mfspr r4,SPRN_DBAT7U
+ stw r4,SL_DBAT7(r1)
+ mfspr r4,SPRN_DBAT7L
+ stw r4,SL_DBAT7+4(r1)
+ mfspr r4,SPRN_IBAT4U
+ stw r4,SL_IBAT4(r1)
+ mfspr r4,SPRN_IBAT4L
+ stw r4,SL_IBAT4+4(r1)
+ mfspr r4,SPRN_IBAT5U
+ stw r4,SL_IBAT5(r1)
+ mfspr r4,SPRN_IBAT5L
+ stw r4,SL_IBAT5+4(r1)
+ mfspr r4,SPRN_IBAT6U
+ stw r4,SL_IBAT6(r1)
+ mfspr r4,SPRN_IBAT6L
+ stw r4,SL_IBAT6+4(r1)
+ mfspr r4,SPRN_IBAT7U
+ stw r4,SL_IBAT7(r1)
+ mfspr r4,SPRN_IBAT7L
+ stw r4,SL_IBAT7+4(r1)
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
+
/* Backup various CPU config stuffs */
bl __save_cpu_setup
@@ -326,22 +369,37 @@
mtibatl 3,r4
BEGIN_MMU_FTR_SECTION
- li r4,0
+ lwz r4,SL_DBAT4(r1)
mtspr SPRN_DBAT4U,r4
+ lwz r4,SL_DBAT4+4(r1)
mtspr SPRN_DBAT4L,r4
+ lwz r4,SL_DBAT5(r1)
mtspr SPRN_DBAT5U,r4
+ lwz r4,SL_DBAT5+4(r1)
mtspr SPRN_DBAT5L,r4
+ lwz r4,SL_DBAT6(r1)
mtspr SPRN_DBAT6U,r4
+ lwz r4,SL_DBAT6+4(r1)
mtspr SPRN_DBAT6L,r4
+ lwz r4,SL_DBAT7(r1)
mtspr SPRN_DBAT7U,r4
+ lwz r4,SL_DBAT7+4(r1)
mtspr SPRN_DBAT7L,r4
+ lwz r4,SL_IBAT4(r1)
mtspr SPRN_IBAT4U,r4
+ lwz r4,SL_IBAT4+4(r1)
mtspr SPRN_IBAT4L,r4
+ lwz r4,SL_IBAT5(r1)
mtspr SPRN_IBAT5U,r4
+ lwz r4,SL_IBAT5+4(r1)
mtspr SPRN_IBAT5L,r4
+ lwz r4,SL_IBAT6(r1)
mtspr SPRN_IBAT6U,r4
+ lwz r4,SL_IBAT6+4(r1)
mtspr SPRN_IBAT6L,r4
+ lwz r4,SL_IBAT7(r1)
mtspr SPRN_IBAT7U,r4
+ lwz r4,SL_IBAT7+4(r1)
mtspr SPRN_IBAT7L,r4
END_MMU_FTR_SECTION_IFSET(MMU_FTR_USE_HIGH_BATS)
diff --git a/arch/powerpc/platforms/powernv/npu-dma.c b/arch/powerpc/platforms/powernv/npu-dma.c
index 8006c54..fd8166f 100644
--- a/arch/powerpc/platforms/powernv/npu-dma.c
+++ b/arch/powerpc/platforms/powernv/npu-dma.c
@@ -56,9 +56,22 @@ static struct dentry *atsd_threshold_dentry;
static struct pci_dev *get_pci_dev(struct device_node *dn)
{
struct pci_dn *pdn = PCI_DN(dn);
+ struct pci_dev *pdev;
- return pci_get_domain_bus_and_slot(pci_domain_nr(pdn->phb->bus),
+ pdev = pci_get_domain_bus_and_slot(pci_domain_nr(pdn->phb->bus),
pdn->busno, pdn->devfn);
+
+ /*
+ * pci_get_domain_bus_and_slot() increased the reference count of
+ * the PCI device, but callers don't need that actually as the PE
+ * already holds a reference to the device. Since callers aren't
+ * aware of the reference count change, call pci_dev_put() now to
+ * avoid leaks.
+ */
+ if (pdev)
+ pci_dev_put(pdev);
+
+ return pdev;
}
/* Given a NPU device get the associated PCI device. */
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
index e4c658c..f99cd31 100644
--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
+++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
@@ -1012,6 +1012,9 @@ static int pseries_update_drconf_memory(struct of_reconfig_data *pr)
if (!memblock_size)
return -EINVAL;
+ if (!pr->old_prop)
+ return 0;
+
p = (__be32 *) pr->old_prop->value;
if (!p)
return -EINVAL;
diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c
index f0e30dc..7b60fcf 100644
--- a/arch/powerpc/platforms/pseries/mobility.c
+++ b/arch/powerpc/platforms/pseries/mobility.c
@@ -9,6 +9,7 @@
* 2 as published by the Free Software Foundation.
*/
+#include <linux/cpu.h>
#include <linux/kernel.h>
#include <linux/kobject.h>
#include <linux/smp.h>
@@ -344,11 +345,19 @@ void post_mobility_fixup(void)
if (rc)
printk(KERN_ERR "Post-mobility activate-fw failed: %d\n", rc);
+ /*
+ * We don't want CPUs to go online/offline while the device
+ * tree is being updated.
+ */
+ cpus_read_lock();
+
rc = pseries_devicetree_update(MIGRATION_SCOPE);
if (rc)
printk(KERN_ERR "Post-mobility device tree update "
"failed: %d\n", rc);
+ cpus_read_unlock();
+
/* Possibly switch to a new RFI flush type */
pseries_setup_rfi_flush();
diff --git a/arch/powerpc/sysdev/xive/common.c b/arch/powerpc/sysdev/xive/common.c
index 959a2a6..0b24b10 100644
--- a/arch/powerpc/sysdev/xive/common.c
+++ b/arch/powerpc/sysdev/xive/common.c
@@ -483,7 +483,7 @@ static int xive_find_target_in_mask(const struct cpumask *mask,
* Now go through the entire mask until we find a valid
* target.
*/
- for (;;) {
+ do {
/*
* We re-check online as the fallback case passes us
* an untested affinity mask
@@ -491,12 +491,11 @@ static int xive_find_target_in_mask(const struct cpumask *mask,
if (cpu_online(cpu) && xive_try_pick_target(cpu))
return cpu;
cpu = cpumask_next(cpu, mask);
- if (cpu == first)
- break;
/* Wrap around */
if (cpu >= nr_cpu_ids)
cpu = cpumask_first(mask);
- }
+ } while (cpu != first);
+
return -1;
}
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index dd6badc..74cfc1b 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -466,8 +466,10 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
local_irq_save(flags);
hard_irq_disable();
- tracing_enabled = tracing_is_on();
- tracing_off();
+ if (!fromipi) {
+ tracing_enabled = tracing_is_on();
+ tracing_off();
+ }
bp = in_breakpoint_table(regs->nip, &offset);
if (bp != NULL) {
diff --git a/arch/riscv/lib/delay.c b/arch/riscv/lib/delay.c
index dce8ae2..ee6853c 100644
--- a/arch/riscv/lib/delay.c
+++ b/arch/riscv/lib/delay.c
@@ -88,7 +88,7 @@ EXPORT_SYMBOL(__delay);
void udelay(unsigned long usecs)
{
- unsigned long ucycles = usecs * lpj_fine * UDELAY_MULT;
+ u64 ucycles = (u64)usecs * lpj_fine * UDELAY_MULT;
if (unlikely(usecs > MAX_UDELAY_US)) {
__delay((u64)usecs * riscv_timebase / 1000000ULL);
diff --git a/arch/s390/Makefile b/arch/s390/Makefile
index ee65185..e6c2e89 100644
--- a/arch/s390/Makefile
+++ b/arch/s390/Makefile
@@ -24,6 +24,7 @@
KBUILD_CFLAGS_DECOMPRESSOR += -fno-delete-null-pointer-checks -msoft-float
KBUILD_CFLAGS_DECOMPRESSOR += -fno-asynchronous-unwind-tables
KBUILD_CFLAGS_DECOMPRESSOR += $(call cc-option,-ffreestanding)
+KBUILD_CFLAGS_DECOMPRESSOR += $(call cc-disable-warning, address-of-packed-member)
KBUILD_CFLAGS_DECOMPRESSOR += $(if $(CONFIG_DEBUG_INFO),-g)
KBUILD_CFLAGS_DECOMPRESSOR += $(if $(CONFIG_DEBUG_INFO_DWARF4), $(call cc-option, -gdwarf-4,))
UTS_MACHINE := s390x
diff --git a/arch/s390/include/asm/facility.h b/arch/s390/include/asm/facility.h
index 99c8ce3..7ffbc5d7 100644
--- a/arch/s390/include/asm/facility.h
+++ b/arch/s390/include/asm/facility.h
@@ -59,6 +59,18 @@ static inline int test_facility(unsigned long nr)
return __test_facility(nr, &S390_lowcore.stfle_fac_list);
}
+static inline unsigned long __stfle_asm(u64 *stfle_fac_list, int size)
+{
+ register unsigned long reg0 asm("0") = size - 1;
+
+ asm volatile(
+ ".insn s,0xb2b00000,0(%1)" /* stfle */
+ : "+d" (reg0)
+ : "a" (stfle_fac_list)
+ : "memory", "cc");
+ return reg0;
+}
+
/**
* stfle - Store facility list extended
* @stfle_fac_list: array where facility list can be stored
@@ -76,13 +88,8 @@ static inline void stfle(u64 *stfle_fac_list, int size)
memcpy(stfle_fac_list, &S390_lowcore.stfl_fac_list, 4);
if (S390_lowcore.stfl_fac_list & 0x01000000) {
/* More facility bits available with stfle */
- register unsigned long reg0 asm("0") = size - 1;
-
- asm volatile(".insn s,0xb2b00000,0(%1)" /* stfle */
- : "+d" (reg0)
- : "a" (stfle_fac_list)
- : "memory", "cc");
- nr = (reg0 + 1) * 8; /* # bytes stored by stfle */
+ nr = __stfle_asm(stfle_fac_list, size);
+ nr = min_t(unsigned long, (nr + 1) * 8, size * 8);
}
memset((char *) stfle_fac_list + nr, 0, size * 8 - nr);
preempt_enable();
diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig
index 6394b4f..f42feab 100644
--- a/arch/sh/boards/Kconfig
+++ b/arch/sh/boards/Kconfig
@@ -8,27 +8,19 @@
bool
config SH_DEVICE_TREE
- bool "Board Described by Device Tree"
+ bool
select OF
select OF_EARLY_FLATTREE
select TIMER_OF
select COMMON_CLK
select GENERIC_CALIBRATE_DELAY
- help
- Select Board Described by Device Tree to build a kernel that
- does not hard-code any board-specific knowledge but instead uses
- a device tree blob provided by the boot-loader. You must enable
- drivers for any hardware you want to use separately. At this
- time, only boards based on the open-hardware J-Core processors
- have sufficient driver coverage to use this option; do not
- select it if you are using original SuperH hardware.
config SH_JCORE_SOC
bool "J-Core SoC"
- depends on SH_DEVICE_TREE && (CPU_SH2 || CPU_J2)
+ select SH_DEVICE_TREE
select CLKSRC_JCORE_PIT
select JCORE_AIC
- default y if CPU_J2
+ depends on CPU_J2
help
Select this option to include drivers core components of the
J-Core SoC, including interrupt controllers and timers.
diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h
index 98cb8c8..0ae60d68 100644
--- a/arch/sh/include/asm/io.h
+++ b/arch/sh/include/asm/io.h
@@ -371,7 +371,11 @@ static inline int iounmap_fixed(void __iomem *addr) { return -EINVAL; }
#define ioremap_nocache ioremap
#define ioremap_uc ioremap
-#define iounmap __iounmap
+
+static inline void iounmap(void __iomem *addr)
+{
+ __iounmap(addr);
+}
/*
* Convert a physical pointer to a virtual kernel pointer for /dev/mem
diff --git a/arch/um/include/asm/mmu_context.h b/arch/um/include/asm/mmu_context.h
index fca34b2..129fb1d 100644
--- a/arch/um/include/asm/mmu_context.h
+++ b/arch/um/include/asm/mmu_context.h
@@ -53,7 +53,7 @@ static inline void activate_mm(struct mm_struct *old, struct mm_struct *new)
* when the new ->mm is used for the first time.
*/
__switch_mm(&new->context.id);
- down_write(&new->mmap_sem);
+ down_write_nested(&new->mmap_sem, 1);
uml_setup_stubs(new);
up_write(&new->mmap_sem);
}
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
index 8dd1d5c..0387d7a 100644
--- a/arch/x86/boot/compressed/misc.c
+++ b/arch/x86/boot/compressed/misc.c
@@ -17,6 +17,7 @@
#include "pgtable.h"
#include "../string.h"
#include "../voffset.h"
+#include <asm/bootparam_utils.h>
/*
* WARNING!!
diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h
index a423bdb..47fd18d 100644
--- a/arch/x86/boot/compressed/misc.h
+++ b/arch/x86/boot/compressed/misc.h
@@ -22,7 +22,6 @@
#include <asm/page.h>
#include <asm/boot.h>
#include <asm/bootparam.h>
-#include <asm/bootparam_utils.h>
#define BOOT_BOOT_H
#include "../ctype.h"
diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig
index cc01102..c3ab808 100644
--- a/arch/x86/configs/x86_64_cuttlefish_defconfig
+++ b/arch/x86/configs/x86_64_cuttlefish_defconfig
@@ -406,6 +406,7 @@
# CONFIG_PWRSEQ_SIMPLE is not set
# CONFIG_MMC_BLOCK is not set
CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_TEST=y
CONFIG_SW_SYNC=y
CONFIG_VIRTIO_PCI=y
CONFIG_VIRTIO_BALLOON=y
diff --git a/arch/x86/entry/calling.h b/arch/x86/entry/calling.h
index e699b20..578b545 100644
--- a/arch/x86/entry/calling.h
+++ b/arch/x86/entry/calling.h
@@ -329,6 +329,23 @@ For 32-bit we have the following conventions - kernel is built with
#endif
+/*
+ * Mitigate Spectre v1 for conditional swapgs code paths.
+ *
+ * FENCE_SWAPGS_USER_ENTRY is used in the user entry swapgs code path, to
+ * prevent a speculative swapgs when coming from kernel space.
+ *
+ * FENCE_SWAPGS_KERNEL_ENTRY is used in the kernel entry non-swapgs code path,
+ * to prevent the swapgs from getting speculatively skipped when coming from
+ * user space.
+ */
+.macro FENCE_SWAPGS_USER_ENTRY
+ ALTERNATIVE "", "lfence", X86_FEATURE_FENCE_SWAPGS_USER
+.endm
+.macro FENCE_SWAPGS_KERNEL_ENTRY
+ ALTERNATIVE "", "lfence", X86_FEATURE_FENCE_SWAPGS_KERNEL
+.endm
+
#endif /* CONFIG_X86_64 */
/*
diff --git a/arch/x86/entry/entry_32.S b/arch/x86/entry/entry_32.S
index b5c2b10..8059d4f 100644
--- a/arch/x86/entry/entry_32.S
+++ b/arch/x86/entry/entry_32.S
@@ -1098,6 +1098,30 @@
.endr
END(irq_entries_start)
+#ifdef CONFIG_X86_LOCAL_APIC
+ .align 8
+ENTRY(spurious_entries_start)
+ vector=FIRST_SYSTEM_VECTOR
+ .rept (NR_VECTORS - FIRST_SYSTEM_VECTOR)
+ pushl $(~vector+0x80) /* Note: always in signed byte range */
+ vector=vector+1
+ jmp common_spurious
+ .align 8
+ .endr
+END(spurious_entries_start)
+
+common_spurious:
+ ASM_CLAC
+ addl $-0x80, (%esp) /* Adjust vector into the [-256, -1] range */
+ SAVE_ALL switch_stacks=1
+ ENCODE_FRAME_POINTER
+ TRACE_IRQS_OFF
+ movl %esp, %eax
+ call smp_spurious_interrupt
+ jmp ret_from_intr
+ENDPROC(common_spurious)
+#endif
+
/*
* the CPU automatically disables interrupts when executing an IRQ vector,
* so IRQ-flags tracing has to follow that:
diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S
index c90e00d..ccb5e34 100644
--- a/arch/x86/entry/entry_64.S
+++ b/arch/x86/entry/entry_64.S
@@ -438,6 +438,18 @@
.endr
END(irq_entries_start)
+ .align 8
+ENTRY(spurious_entries_start)
+ vector=FIRST_SYSTEM_VECTOR
+ .rept (NR_VECTORS - FIRST_SYSTEM_VECTOR)
+ UNWIND_HINT_IRET_REGS
+ pushq $(~vector+0x80) /* Note: always in signed byte range */
+ jmp common_spurious
+ .align 8
+ vector=vector+1
+ .endr
+END(spurious_entries_start)
+
.macro DEBUG_ENTRY_ASSERT_IRQS_OFF
#ifdef CONFIG_DEBUG_ENTRY
pushq %rax
@@ -570,7 +582,7 @@
testb $3, CS-ORIG_RAX+8(%rsp)
jz 1f
SWAPGS
-
+ FENCE_SWAPGS_USER_ENTRY
/*
* Switch to the thread stack. The IRET frame and orig_ax are
* on the stack, as well as the return address. RDI..R12 are
@@ -600,8 +612,10 @@
UNWIND_HINT_FUNC
movq (%rdi), %rdi
+ jmp 2f
1:
-
+ FENCE_SWAPGS_KERNEL_ENTRY
+2:
PUSH_AND_CLEAR_REGS save_ret=1
ENCODE_FRAME_POINTER 8
@@ -634,10 +648,20 @@
/* Interrupt entry/exit. */
- /*
- * The interrupt stubs push (~vector+0x80) onto the stack and
- * then jump to common_interrupt.
- */
+/*
+ * The interrupt stubs push (~vector+0x80) onto the stack and
+ * then jump to common_spurious/interrupt.
+ */
+common_spurious:
+ addq $-0x80, (%rsp) /* Adjust vector to [-256, -1] range */
+ call interrupt_entry
+ UNWIND_HINT_REGS indirect=1
+ call smp_spurious_interrupt /* rdi points to pt_regs */
+ jmp ret_from_intr
+END(common_spurious)
+_ASM_NOKPROBE(common_spurious)
+
+/* common_interrupt is a hotpath. Align it */
.p2align CONFIG_X86_L1_CACHE_SHIFT
common_interrupt:
addq $-0x80, (%rsp) /* Adjust vector to [-256, -1] range */
@@ -1174,7 +1198,6 @@
#ifdef CONFIG_XEN
idtentry xennmi do_nmi has_error_code=0
idtentry xendebug do_debug has_error_code=0
-idtentry xenint3 do_int3 has_error_code=0
#endif
idtentry general_protection do_general_protection has_error_code=1
@@ -1219,6 +1242,13 @@
*/
SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg=%rax save_reg=%r14
+ /*
+ * The above SAVE_AND_SWITCH_TO_KERNEL_CR3 macro doesn't do an
+ * unconditional CR3 write, even in the PTI case. So do an lfence
+ * to prevent GS speculation, regardless of whether PTI is enabled.
+ */
+ FENCE_SWAPGS_KERNEL_ENTRY
+
ret
END(paranoid_entry)
@@ -1269,6 +1299,7 @@
* from user mode due to an IRET fault.
*/
SWAPGS
+ FENCE_SWAPGS_USER_ENTRY
/* We have user CR3. Change to kernel CR3. */
SWITCH_TO_KERNEL_CR3 scratch_reg=%rax
@@ -1290,6 +1321,8 @@
CALL_enter_from_user_mode
ret
+.Lerror_entry_done_lfence:
+ FENCE_SWAPGS_KERNEL_ENTRY
.Lerror_entry_done:
TRACE_IRQS_OFF
ret
@@ -1308,7 +1341,7 @@
cmpq %rax, RIP+8(%rsp)
je .Lbstep_iret
cmpq $.Lgs_change, RIP+8(%rsp)
- jne .Lerror_entry_done
+ jne .Lerror_entry_done_lfence
/*
* hack: .Lgs_change can fail with user gsbase. If this happens, fix up
@@ -1316,6 +1349,7 @@
* .Lgs_change's error handler with kernel gsbase.
*/
SWAPGS
+ FENCE_SWAPGS_USER_ENTRY
SWITCH_TO_KERNEL_CR3 scratch_reg=%rax
jmp .Lerror_entry_done
@@ -1330,6 +1364,7 @@
* gsbase and CR3. Switch to kernel gsbase and CR3:
*/
SWAPGS
+ FENCE_SWAPGS_USER_ENTRY
SWITCH_TO_KERNEL_CR3 scratch_reg=%rax
/*
@@ -1421,6 +1456,7 @@
swapgs
cld
+ FENCE_SWAPGS_USER_ENTRY
SWITCH_TO_KERNEL_CR3 scratch_reg=%rdx
movq %rsp, %rdx
movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp
diff --git a/arch/x86/entry/vdso/vclock_gettime.c b/arch/x86/entry/vdso/vclock_gettime.c
index e48ca3af..8a88e73 100644
--- a/arch/x86/entry/vdso/vclock_gettime.c
+++ b/arch/x86/entry/vdso/vclock_gettime.c
@@ -29,12 +29,12 @@ extern int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz);
extern time_t __vdso_time(time_t *t);
#ifdef CONFIG_PARAVIRT_CLOCK
-extern u8 pvclock_page
+extern u8 pvclock_page[PAGE_SIZE]
__attribute__((visibility("hidden")));
#endif
#ifdef CONFIG_HYPERV_TSCPAGE
-extern u8 hvclock_page
+extern u8 hvclock_page[PAGE_SIZE]
__attribute__((visibility("hidden")));
#endif
@@ -191,13 +191,24 @@ notrace static inline u64 vgetsns(int *mode)
if (gtod->vclock_mode == VCLOCK_TSC)
cycles = vread_tsc();
+
+ /*
+ * For any memory-mapped vclock type, we need to make sure that gcc
+ * doesn't cleverly hoist a load before the mode check. Otherwise we
+ * might end up touching the memory-mapped page even if the vclock in
+ * question isn't enabled, which will segfault. Hence the barriers.
+ */
#ifdef CONFIG_PARAVIRT_CLOCK
- else if (gtod->vclock_mode == VCLOCK_PVCLOCK)
+ else if (gtod->vclock_mode == VCLOCK_PVCLOCK) {
+ barrier();
cycles = vread_pvclock(mode);
+ }
#endif
#ifdef CONFIG_HYPERV_TSCPAGE
- else if (gtod->vclock_mode == VCLOCK_HVCLOCK)
+ else if (gtod->vclock_mode == VCLOCK_HVCLOCK) {
+ barrier();
cycles = vread_hvclock(mode);
+ }
#endif
else
return 0;
diff --git a/arch/x86/events/amd/uncore.c b/arch/x86/events/amd/uncore.c
index 8671de1..baa7e36 100644
--- a/arch/x86/events/amd/uncore.c
+++ b/arch/x86/events/amd/uncore.c
@@ -210,15 +210,22 @@ static int amd_uncore_event_init(struct perf_event *event)
hwc->config = event->attr.config & AMD64_RAW_EVENT_MASK_NB;
hwc->idx = -1;
+ if (event->cpu < 0)
+ return -EINVAL;
+
/*
* SliceMask and ThreadMask need to be set for certain L3 events in
* Family 17h. For other events, the two fields do not affect the count.
*/
- if (l3_mask)
- hwc->config |= (AMD64_L3_SLICE_MASK | AMD64_L3_THREAD_MASK);
+ if (l3_mask && is_llc_event(event)) {
+ int thread = 2 * (cpu_data(event->cpu).cpu_core_id % 4);
- if (event->cpu < 0)
- return -EINVAL;
+ if (smp_num_siblings > 1)
+ thread += cpu_data(event->cpu).apicid & 1;
+
+ hwc->config |= (1ULL << (AMD64_L3_THREAD_SHIFT + thread) &
+ AMD64_L3_THREAD_MASK) | AMD64_L3_SLICE_MASK;
+ }
uncore = event_to_amd_uncore(event);
if (!uncore)
diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
index c8b0bf2..db5a2ba 100644
--- a/arch/x86/events/intel/core.c
+++ b/arch/x86/events/intel/core.c
@@ -2074,12 +2074,10 @@ static void intel_pmu_disable_event(struct perf_event *event)
cpuc->intel_ctrl_host_mask &= ~(1ull << hwc->idx);
cpuc->intel_cp_status &= ~(1ull << hwc->idx);
- if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL)) {
+ if (unlikely(hwc->config_base == MSR_ARCH_PERFMON_FIXED_CTR_CTRL))
intel_pmu_disable_fixed(hwc);
- return;
- }
-
- x86_pmu_disable_event(event);
+ else
+ x86_pmu_disable_event(event);
/*
* Needs to be called after x86_pmu_disable_event,
diff --git a/arch/x86/events/intel/uncore.h b/arch/x86/events/intel/uncore.h
index cc6dd4f..42fa397 100644
--- a/arch/x86/events/intel/uncore.h
+++ b/arch/x86/events/intel/uncore.h
@@ -402,6 +402,16 @@ static inline bool is_freerunning_event(struct perf_event *event)
(((cfg >> 8) & 0xff) >= UNCORE_FREERUNNING_UMASK_START);
}
+/* Check and reject invalid config */
+static inline int uncore_freerunning_hw_config(struct intel_uncore_box *box,
+ struct perf_event *event)
+{
+ if (is_freerunning_event(event))
+ return 0;
+
+ return -EINVAL;
+}
+
static inline void uncore_disable_box(struct intel_uncore_box *box)
{
if (box->pmu->type->ops->disable_box)
diff --git a/arch/x86/events/intel/uncore_snbep.c b/arch/x86/events/intel/uncore_snbep.c
index b10e043..8e4e8e4 100644
--- a/arch/x86/events/intel/uncore_snbep.c
+++ b/arch/x86/events/intel/uncore_snbep.c
@@ -3585,6 +3585,7 @@ static struct uncore_event_desc skx_uncore_iio_freerunning_events[] = {
static struct intel_uncore_ops skx_uncore_iio_freerunning_ops = {
.read_counter = uncore_msr_read_counter,
+ .hw_config = uncore_freerunning_hw_config,
};
static struct attribute *skx_uncore_iio_freerunning_formats_attr[] = {
diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index 130e81e..050368d 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -48,7 +48,7 @@ static inline void generic_apic_probe(void)
#ifdef CONFIG_X86_LOCAL_APIC
-extern unsigned int apic_verbosity;
+extern int apic_verbosity;
extern int local_apic_timer_c2_ok;
extern int disable_apic;
diff --git a/arch/x86/include/asm/atomic.h b/arch/x86/include/asm/atomic.h
index ce84388..d266a40 100644
--- a/arch/x86/include/asm/atomic.h
+++ b/arch/x86/include/asm/atomic.h
@@ -54,7 +54,7 @@ static __always_inline void arch_atomic_add(int i, atomic_t *v)
{
asm volatile(LOCK_PREFIX "addl %1,%0"
: "+m" (v->counter)
- : "ir" (i));
+ : "ir" (i) : "memory");
}
/**
@@ -68,7 +68,7 @@ static __always_inline void arch_atomic_sub(int i, atomic_t *v)
{
asm volatile(LOCK_PREFIX "subl %1,%0"
: "+m" (v->counter)
- : "ir" (i));
+ : "ir" (i) : "memory");
}
/**
@@ -95,7 +95,7 @@ static __always_inline bool arch_atomic_sub_and_test(int i, atomic_t *v)
static __always_inline void arch_atomic_inc(atomic_t *v)
{
asm volatile(LOCK_PREFIX "incl %0"
- : "+m" (v->counter));
+ : "+m" (v->counter) :: "memory");
}
#define arch_atomic_inc arch_atomic_inc
@@ -108,7 +108,7 @@ static __always_inline void arch_atomic_inc(atomic_t *v)
static __always_inline void arch_atomic_dec(atomic_t *v)
{
asm volatile(LOCK_PREFIX "decl %0"
- : "+m" (v->counter));
+ : "+m" (v->counter) :: "memory");
}
#define arch_atomic_dec arch_atomic_dec
diff --git a/arch/x86/include/asm/atomic64_64.h b/arch/x86/include/asm/atomic64_64.h
index 5f851d9..55ca027 100644
--- a/arch/x86/include/asm/atomic64_64.h
+++ b/arch/x86/include/asm/atomic64_64.h
@@ -45,7 +45,7 @@ static __always_inline void arch_atomic64_add(long i, atomic64_t *v)
{
asm volatile(LOCK_PREFIX "addq %1,%0"
: "=m" (v->counter)
- : "er" (i), "m" (v->counter));
+ : "er" (i), "m" (v->counter) : "memory");
}
/**
@@ -59,7 +59,7 @@ static inline void arch_atomic64_sub(long i, atomic64_t *v)
{
asm volatile(LOCK_PREFIX "subq %1,%0"
: "=m" (v->counter)
- : "er" (i), "m" (v->counter));
+ : "er" (i), "m" (v->counter) : "memory");
}
/**
@@ -87,7 +87,7 @@ static __always_inline void arch_atomic64_inc(atomic64_t *v)
{
asm volatile(LOCK_PREFIX "incq %0"
: "=m" (v->counter)
- : "m" (v->counter));
+ : "m" (v->counter) : "memory");
}
#define arch_atomic64_inc arch_atomic64_inc
@@ -101,7 +101,7 @@ static __always_inline void arch_atomic64_dec(atomic64_t *v)
{
asm volatile(LOCK_PREFIX "decq %0"
: "=m" (v->counter)
- : "m" (v->counter));
+ : "m" (v->counter) : "memory");
}
#define arch_atomic64_dec arch_atomic64_dec
diff --git a/arch/x86/include/asm/barrier.h b/arch/x86/include/asm/barrier.h
index 14de043..84f848c 100644
--- a/arch/x86/include/asm/barrier.h
+++ b/arch/x86/include/asm/barrier.h
@@ -80,8 +80,8 @@ do { \
})
/* Atomic operations are already serializing on x86 */
-#define __smp_mb__before_atomic() barrier()
-#define __smp_mb__after_atomic() barrier()
+#define __smp_mb__before_atomic() do { } while (0)
+#define __smp_mb__after_atomic() do { } while (0)
#include <asm-generic/barrier.h>
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index 117644d..5694825 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -22,8 +22,8 @@ enum cpuid_leafs
CPUID_LNX_3,
CPUID_7_0_EBX,
CPUID_D_1_EAX,
- CPUID_F_0_EDX,
- CPUID_F_1_EDX,
+ CPUID_LNX_4,
+ CPUID_DUMMY,
CPUID_8000_0008_EBX,
CPUID_6_EAX,
CPUID_8000_000A_EDX,
diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
index 69037da..759f0a1 100644
--- a/arch/x86/include/asm/cpufeatures.h
+++ b/arch/x86/include/asm/cpufeatures.h
@@ -239,12 +239,14 @@
#define X86_FEATURE_BMI1 ( 9*32+ 3) /* 1st group bit manipulation extensions */
#define X86_FEATURE_HLE ( 9*32+ 4) /* Hardware Lock Elision */
#define X86_FEATURE_AVX2 ( 9*32+ 5) /* AVX2 instructions */
+#define X86_FEATURE_FDP_EXCPTN_ONLY ( 9*32+ 6) /* "" FPU data pointer updated only on x87 exceptions */
#define X86_FEATURE_SMEP ( 9*32+ 7) /* Supervisor Mode Execution Protection */
#define X86_FEATURE_BMI2 ( 9*32+ 8) /* 2nd group bit manipulation extensions */
#define X86_FEATURE_ERMS ( 9*32+ 9) /* Enhanced REP MOVSB/STOSB instructions */
#define X86_FEATURE_INVPCID ( 9*32+10) /* Invalidate Processor Context ID */
#define X86_FEATURE_RTM ( 9*32+11) /* Restricted Transactional Memory */
#define X86_FEATURE_CQM ( 9*32+12) /* Cache QoS Monitoring */
+#define X86_FEATURE_ZERO_FCS_FDS ( 9*32+13) /* "" Zero out FPU CS and FPU DS */
#define X86_FEATURE_MPX ( 9*32+14) /* Memory Protection Extension */
#define X86_FEATURE_RDT_A ( 9*32+15) /* Resource Director Technology Allocation */
#define X86_FEATURE_AVX512F ( 9*32+16) /* AVX-512 Foundation */
@@ -269,13 +271,18 @@
#define X86_FEATURE_XGETBV1 (10*32+ 2) /* XGETBV with ECX = 1 instruction */
#define X86_FEATURE_XSAVES (10*32+ 3) /* XSAVES/XRSTORS instructions */
-/* Intel-defined CPU QoS Sub-leaf, CPUID level 0x0000000F:0 (EDX), word 11 */
-#define X86_FEATURE_CQM_LLC (11*32+ 1) /* LLC QoS if 1 */
-
-/* Intel-defined CPU QoS Sub-leaf, CPUID level 0x0000000F:1 (EDX), word 12 */
-#define X86_FEATURE_CQM_OCCUP_LLC (12*32+ 0) /* LLC occupancy monitoring */
-#define X86_FEATURE_CQM_MBM_TOTAL (12*32+ 1) /* LLC Total MBM monitoring */
-#define X86_FEATURE_CQM_MBM_LOCAL (12*32+ 2) /* LLC Local MBM monitoring */
+/*
+ * Extended auxiliary flags: Linux defined - for features scattered in various
+ * CPUID levels like 0xf, etc.
+ *
+ * Reuse free bits when adding new feature flags!
+ */
+#define X86_FEATURE_CQM_LLC (11*32+ 0) /* LLC QoS if 1 */
+#define X86_FEATURE_CQM_OCCUP_LLC (11*32+ 1) /* LLC occupancy monitoring */
+#define X86_FEATURE_CQM_MBM_TOTAL (11*32+ 2) /* LLC Total MBM monitoring */
+#define X86_FEATURE_CQM_MBM_LOCAL (11*32+ 3) /* LLC Local MBM monitoring */
+#define X86_FEATURE_FENCE_SWAPGS_USER (11*32+ 4) /* "" LFENCE in user entry SWAPGS path */
+#define X86_FEATURE_FENCE_SWAPGS_KERNEL (11*32+ 5) /* "" LFENCE in kernel entry SWAPGS path */
/* AMD-defined CPU features, CPUID level 0x80000008 (EBX), word 13 */
#define X86_FEATURE_CLZERO (13*32+ 0) /* CLZERO instruction */
@@ -381,5 +388,6 @@
#define X86_BUG_L1TF X86_BUG(18) /* CPU is affected by L1 Terminal Fault */
#define X86_BUG_MDS X86_BUG(19) /* CPU is affected by Microarchitectural data sampling */
#define X86_BUG_MSBDS_ONLY X86_BUG(20) /* CPU is only affected by the MSDBS variant of BUG_MDS */
+#define X86_BUG_SWAPGS X86_BUG(21) /* CPU is affected by speculation through SWAPGS */
#endif /* _ASM_X86_CPUFEATURES_H */
diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h
index 32e666e..cbd97e2 100644
--- a/arch/x86/include/asm/hw_irq.h
+++ b/arch/x86/include/asm/hw_irq.h
@@ -150,8 +150,11 @@ extern char irq_entries_start[];
#define trace_irq_entries_start irq_entries_start
#endif
+extern char spurious_entries_start[];
+
#define VECTOR_UNUSED NULL
-#define VECTOR_RETRIGGERED ((void *)~0UL)
+#define VECTOR_SHUTDOWN ((void *)~0UL)
+#define VECTOR_RETRIGGERED ((void *)~1UL)
typedef struct irq_desc* vector_irq_t[NR_VECTORS];
DECLARE_PER_CPU(vector_irq_t, vector_irq);
diff --git a/arch/x86/include/asm/intel-family.h b/arch/x86/include/asm/intel-family.h
index 2e38fb8..aebedba 100644
--- a/arch/x86/include/asm/intel-family.h
+++ b/arch/x86/include/asm/intel-family.h
@@ -56,6 +56,7 @@
#define INTEL_FAM6_ICELAKE_XEON_D 0x6C
#define INTEL_FAM6_ICELAKE_DESKTOP 0x7D
#define INTEL_FAM6_ICELAKE_MOBILE 0x7E
+#define INTEL_FAM6_ICELAKE_NNPI 0x9D
/* "Small Core" Processors (Atom) */
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 7014dba..2877e1fba 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1427,25 +1427,29 @@ enum {
#define kvm_arch_vcpu_memslots_id(vcpu) ((vcpu)->arch.hflags & HF_SMM_MASK ? 1 : 0)
#define kvm_memslots_for_spte_role(kvm, role) __kvm_memslots(kvm, (role).smm)
+asmlinkage void __noreturn kvm_spurious_fault(void);
+
/*
* Hardware virtualization extension instructions may fault if a
* reboot turns off virtualization while processes are running.
- * Trap the fault and ignore the instruction if that happens.
+ * Usually after catching the fault we just panic; during reboot
+ * instead the instruction is ignored.
*/
-asmlinkage void kvm_spurious_fault(void);
-
-#define ____kvm_handle_fault_on_reboot(insn, cleanup_insn) \
- "666: " insn "\n\t" \
- "668: \n\t" \
- ".pushsection .fixup, \"ax\" \n" \
- "667: \n\t" \
- cleanup_insn "\n\t" \
- "cmpb $0, kvm_rebooting \n\t" \
- "jne 668b \n\t" \
- __ASM_SIZE(push) " $666b \n\t" \
- "jmp kvm_spurious_fault \n\t" \
- ".popsection \n\t" \
- _ASM_EXTABLE(666b, 667b)
+#define ____kvm_handle_fault_on_reboot(insn, cleanup_insn) \
+ "666: \n\t" \
+ insn "\n\t" \
+ "jmp 668f \n\t" \
+ "667: \n\t" \
+ "call kvm_spurious_fault \n\t" \
+ "668: \n\t" \
+ ".pushsection .fixup, \"ax\" \n\t" \
+ "700: \n\t" \
+ cleanup_insn "\n\t" \
+ "cmpb $0, kvm_rebooting\n\t" \
+ "je 667b \n\t" \
+ "jmp 668b \n\t" \
+ ".popsection \n\t" \
+ _ASM_EXTABLE(666b, 700b)
#define __kvm_handle_fault_on_reboot(insn) \
____kvm_handle_fault_on_reboot(insn, "")
diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h
index e375d4266..a046770 100644
--- a/arch/x86/include/asm/paravirt.h
+++ b/arch/x86/include/asm/paravirt.h
@@ -768,6 +768,7 @@ static __always_inline bool pv_vcpu_is_preempted(long cpu)
PV_RESTORE_ALL_CALLER_REGS \
FRAME_END \
"ret;" \
+ ".size " PV_THUNK_NAME(func) ", .-" PV_THUNK_NAME(func) ";" \
".popsection")
/* Get a reference to a callee-save function */
diff --git a/arch/x86/include/asm/syscall_wrapper.h b/arch/x86/include/asm/syscall_wrapper.h
index 71e58c8..7eb936b 100644
--- a/arch/x86/include/asm/syscall_wrapper.h
+++ b/arch/x86/include/asm/syscall_wrapper.h
@@ -6,6 +6,8 @@
#ifndef _ASM_X86_SYSCALL_WRAPPER_H
#define _ASM_X86_SYSCALL_WRAPPER_H
+struct pt_regs;
+
/* Mapping of registers to parameters for syscalls on x86-64 and x32 */
#define SC_X86_64_REGS_TO_ARGS(x, ...) \
__MAP(x,__SC_ARGS \
@@ -56,9 +58,15 @@
SYSCALL_ALIAS(__ia32_sys_##sname, __x64_sys_##sname); \
asmlinkage long __x64_sys_##sname(const struct pt_regs *__unused)
-#define COND_SYSCALL(name) \
- cond_syscall(sys_##name); \
- cond_syscall(__ia32_sys_##name)
+#define COND_SYSCALL(name) \
+ asmlinkage __weak long __x64_sys_##name(const struct pt_regs *__unused) \
+ { \
+ return sys_ni_syscall(); \
+ } \
+ asmlinkage __weak long __ia32_sys_##name(const struct pt_regs *__unused)\
+ { \
+ return sys_ni_syscall(); \
+ }
#define SYS_NI(name) \
SYSCALL_ALIAS(sys_##name, sys_ni_posix_timers); \
@@ -196,7 +204,11 @@
#endif
#ifndef COND_SYSCALL
-#define COND_SYSCALL(name) cond_syscall(__x64_sys_##name)
+#define COND_SYSCALL(name) \
+ asmlinkage __weak long __x64_sys_##name(const struct pt_regs *__unused) \
+ { \
+ return sys_ni_syscall(); \
+ }
#endif
#ifndef SYS_NI
@@ -208,9 +220,8 @@
* For VSYSCALLS, we need to declare these three syscalls with the new
* pt_regs-based calling convention for in-kernel use.
*/
-struct pt_regs;
-asmlinkage long sys_getcpu(const struct pt_regs *regs); /* di,si,dx */
-asmlinkage long sys_gettimeofday(const struct pt_regs *regs); /* di,si */
-asmlinkage long sys_time(const struct pt_regs *regs); /* di */
+asmlinkage long __x64_sys_getcpu(const struct pt_regs *regs);
+asmlinkage long __x64_sys_gettimeofday(const struct pt_regs *regs);
+asmlinkage long __x64_sys_time(const struct pt_regs *regs);
#endif /* _ASM_X86_SYSCALL_WRAPPER_H */
diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h
index afbc872..b771bb3d 100644
--- a/arch/x86/include/asm/traps.h
+++ b/arch/x86/include/asm/traps.h
@@ -40,7 +40,7 @@ asmlinkage void simd_coprocessor_error(void);
asmlinkage void xen_divide_error(void);
asmlinkage void xen_xennmi(void);
asmlinkage void xen_xendebug(void);
-asmlinkage void xen_xenint3(void);
+asmlinkage void xen_int3(void);
asmlinkage void xen_overflow(void);
asmlinkage void xen_bounds(void);
asmlinkage void xen_invalid_op(void);
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 84132ed..272a128 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -181,7 +181,7 @@ EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok);
/*
* Debug level, exported for io_apic.c
*/
-unsigned int apic_verbosity;
+int apic_verbosity;
int pic_mode;
@@ -1452,7 +1452,8 @@ static void apic_pending_intr_clear(void)
if (queued) {
if (boot_cpu_has(X86_FEATURE_TSC) && cpu_khz) {
ntsc = rdtsc();
- max_loops = (cpu_khz << 10) - (ntsc - tsc);
+ max_loops = (long long)cpu_khz << 10;
+ max_loops -= ntsc - tsc;
} else {
max_loops--;
}
@@ -2026,21 +2027,32 @@ __visible void __irq_entry smp_spurious_interrupt(struct pt_regs *regs)
entering_irq();
trace_spurious_apic_entry(vector);
- /*
- * Check if this really is a spurious interrupt and ACK it
- * if it is a vectored one. Just in case...
- * Spurious interrupts should not be ACKed.
- */
- v = apic_read(APIC_ISR + ((vector & ~0x1f) >> 1));
- if (v & (1 << (vector & 0x1f)))
- ack_APIC_irq();
-
inc_irq_stat(irq_spurious_count);
- /* see sw-dev-man vol 3, chapter 7.4.13.5 */
- pr_info("spurious APIC interrupt through vector %02x on CPU#%d, "
- "should never happen.\n", vector, smp_processor_id());
+ /*
+ * If this is a spurious interrupt then do not acknowledge
+ */
+ if (vector == SPURIOUS_APIC_VECTOR) {
+ /* See SDM vol 3 */
+ pr_info("Spurious APIC interrupt (vector 0xFF) on CPU#%d, should never happen.\n",
+ smp_processor_id());
+ goto out;
+ }
+ /*
+ * If it is a vectored one, verify it's set in the ISR. If set,
+ * acknowledge it.
+ */
+ v = apic_read(APIC_ISR + ((vector & ~0x1f) >> 1));
+ if (v & (1 << (vector & 0x1f))) {
+ pr_info("Spurious interrupt (vector 0x%02x) on CPU#%d. Acked\n",
+ vector, smp_processor_id());
+ ack_APIC_irq();
+ } else {
+ pr_info("Spurious interrupt (vector 0x%02x) on CPU#%d. Not pending!\n",
+ vector, smp_processor_id());
+ }
+out:
trace_spurious_apic_exit(vector);
exiting_irq();
}
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index ff0d14c..4077e30 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -1891,6 +1891,50 @@ static int ioapic_set_affinity(struct irq_data *irq_data,
return ret;
}
+/*
+ * Interrupt shutdown masks the ioapic pin, but the interrupt might already
+ * be in flight, but not yet serviced by the target CPU. That means
+ * __synchronize_hardirq() would return and claim that everything is calmed
+ * down. So free_irq() would proceed and deactivate the interrupt and free
+ * resources.
+ *
+ * Once the target CPU comes around to service it it will find a cleared
+ * vector and complain. While the spurious interrupt is harmless, the full
+ * release of resources might prevent the interrupt from being acknowledged
+ * which keeps the hardware in a weird state.
+ *
+ * Verify that the corresponding Remote-IRR bits are clear.
+ */
+static int ioapic_irq_get_chip_state(struct irq_data *irqd,
+ enum irqchip_irq_state which,
+ bool *state)
+{
+ struct mp_chip_data *mcd = irqd->chip_data;
+ struct IO_APIC_route_entry rentry;
+ struct irq_pin_list *p;
+
+ if (which != IRQCHIP_STATE_ACTIVE)
+ return -EINVAL;
+
+ *state = false;
+ raw_spin_lock(&ioapic_lock);
+ for_each_irq_pin(p, mcd->irq_2_pin) {
+ rentry = __ioapic_read_entry(p->apic, p->pin);
+ /*
+ * The remote IRR is only valid in level trigger mode. It's
+ * meaning is undefined for edge triggered interrupts and
+ * irrelevant because the IO-APIC treats them as fire and
+ * forget.
+ */
+ if (rentry.irr && rentry.trigger) {
+ *state = true;
+ break;
+ }
+ }
+ raw_spin_unlock(&ioapic_lock);
+ return 0;
+}
+
static struct irq_chip ioapic_chip __read_mostly = {
.name = "IO-APIC",
.irq_startup = startup_ioapic_irq,
@@ -1900,6 +1944,7 @@ static struct irq_chip ioapic_chip __read_mostly = {
.irq_eoi = ioapic_ack_level,
.irq_set_affinity = ioapic_set_affinity,
.irq_retrigger = irq_chip_retrigger_hierarchy,
+ .irq_get_irqchip_state = ioapic_irq_get_chip_state,
.flags = IRQCHIP_SKIP_SET_WAKE,
};
@@ -1912,6 +1957,7 @@ static struct irq_chip ioapic_ir_chip __read_mostly = {
.irq_eoi = ioapic_ir_ack_level,
.irq_set_affinity = ioapic_set_affinity,
.irq_retrigger = irq_chip_retrigger_hierarchy,
+ .irq_get_irqchip_state = ioapic_irq_get_chip_state,
.flags = IRQCHIP_SKIP_SET_WAKE,
};
diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c
index 652e7ff..10e1d17 100644
--- a/arch/x86/kernel/apic/vector.c
+++ b/arch/x86/kernel/apic/vector.c
@@ -342,7 +342,7 @@ static void clear_irq_vector(struct irq_data *irqd)
trace_vector_clear(irqd->irq, vector, apicd->cpu, apicd->prev_vector,
apicd->prev_cpu);
- per_cpu(vector_irq, apicd->cpu)[vector] = VECTOR_UNUSED;
+ per_cpu(vector_irq, apicd->cpu)[vector] = VECTOR_SHUTDOWN;
irq_matrix_free(vector_matrix, apicd->cpu, vector, managed);
apicd->vector = 0;
@@ -351,7 +351,7 @@ static void clear_irq_vector(struct irq_data *irqd)
if (!vector)
return;
- per_cpu(vector_irq, apicd->prev_cpu)[vector] = VECTOR_UNUSED;
+ per_cpu(vector_irq, apicd->prev_cpu)[vector] = VECTOR_SHUTDOWN;
irq_matrix_free(vector_matrix, apicd->prev_cpu, vector, managed);
apicd->prev_vector = 0;
apicd->move_in_progress = 0;
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
index a5cde74..ee7d176 100644
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -32,6 +32,7 @@
#include <asm/e820/api.h>
#include <asm/hypervisor.h>
+static void __init spectre_v1_select_mitigation(void);
static void __init spectre_v2_select_mitigation(void);
static void __init ssb_select_mitigation(void);
static void __init l1tf_select_mitigation(void);
@@ -96,17 +97,11 @@ void __init check_bugs(void)
if (boot_cpu_has(X86_FEATURE_STIBP))
x86_spec_ctrl_mask |= SPEC_CTRL_STIBP;
- /* Select the proper spectre mitigation before patching alternatives */
+ /* Select the proper CPU mitigations before patching alternatives: */
+ spectre_v1_select_mitigation();
spectre_v2_select_mitigation();
-
- /*
- * Select proper mitigation for any exposure to the Speculative Store
- * Bypass vulnerability.
- */
ssb_select_mitigation();
-
l1tf_select_mitigation();
-
mds_select_mitigation();
arch_smt_update();
@@ -272,6 +267,98 @@ static int __init mds_cmdline(char *str)
early_param("mds", mds_cmdline);
#undef pr_fmt
+#define pr_fmt(fmt) "Spectre V1 : " fmt
+
+enum spectre_v1_mitigation {
+ SPECTRE_V1_MITIGATION_NONE,
+ SPECTRE_V1_MITIGATION_AUTO,
+};
+
+static enum spectre_v1_mitigation spectre_v1_mitigation __ro_after_init =
+ SPECTRE_V1_MITIGATION_AUTO;
+
+static const char * const spectre_v1_strings[] = {
+ [SPECTRE_V1_MITIGATION_NONE] = "Vulnerable: __user pointer sanitization and usercopy barriers only; no swapgs barriers",
+ [SPECTRE_V1_MITIGATION_AUTO] = "Mitigation: usercopy/swapgs barriers and __user pointer sanitization",
+};
+
+/*
+ * Does SMAP provide full mitigation against speculative kernel access to
+ * userspace?
+ */
+static bool smap_works_speculatively(void)
+{
+ if (!boot_cpu_has(X86_FEATURE_SMAP))
+ return false;
+
+ /*
+ * On CPUs which are vulnerable to Meltdown, SMAP does not
+ * prevent speculative access to user data in the L1 cache.
+ * Consider SMAP to be non-functional as a mitigation on these
+ * CPUs.
+ */
+ if (boot_cpu_has(X86_BUG_CPU_MELTDOWN))
+ return false;
+
+ return true;
+}
+
+static void __init spectre_v1_select_mitigation(void)
+{
+ if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V1) || cpu_mitigations_off()) {
+ spectre_v1_mitigation = SPECTRE_V1_MITIGATION_NONE;
+ return;
+ }
+
+ if (spectre_v1_mitigation == SPECTRE_V1_MITIGATION_AUTO) {
+ /*
+ * With Spectre v1, a user can speculatively control either
+ * path of a conditional swapgs with a user-controlled GS
+ * value. The mitigation is to add lfences to both code paths.
+ *
+ * If FSGSBASE is enabled, the user can put a kernel address in
+ * GS, in which case SMAP provides no protection.
+ *
+ * [ NOTE: Don't check for X86_FEATURE_FSGSBASE until the
+ * FSGSBASE enablement patches have been merged. ]
+ *
+ * If FSGSBASE is disabled, the user can only put a user space
+ * address in GS. That makes an attack harder, but still
+ * possible if there's no SMAP protection.
+ */
+ if (!smap_works_speculatively()) {
+ /*
+ * Mitigation can be provided from SWAPGS itself or
+ * PTI as the CR3 write in the Meltdown mitigation
+ * is serializing.
+ *
+ * If neither is there, mitigate with an LFENCE to
+ * stop speculation through swapgs.
+ */
+ if (boot_cpu_has_bug(X86_BUG_SWAPGS) &&
+ !boot_cpu_has(X86_FEATURE_PTI))
+ setup_force_cpu_cap(X86_FEATURE_FENCE_SWAPGS_USER);
+
+ /*
+ * Enable lfences in the kernel entry (non-swapgs)
+ * paths, to prevent user entry from speculatively
+ * skipping swapgs.
+ */
+ setup_force_cpu_cap(X86_FEATURE_FENCE_SWAPGS_KERNEL);
+ }
+ }
+
+ pr_info("%s\n", spectre_v1_strings[spectre_v1_mitigation]);
+}
+
+static int __init nospectre_v1_cmdline(char *str)
+{
+ spectre_v1_mitigation = SPECTRE_V1_MITIGATION_NONE;
+ return 0;
+}
+early_param("nospectre_v1", nospectre_v1_cmdline);
+
+#undef pr_fmt
#define pr_fmt(fmt) "Spectre V2 : " fmt
static enum spectre_v2_mitigation spectre_v2_enabled __ro_after_init =
@@ -1196,7 +1283,7 @@ static ssize_t l1tf_show_state(char *buf)
static ssize_t mds_show_state(char *buf)
{
- if (!hypervisor_is_type(X86_HYPER_NATIVE)) {
+ if (boot_cpu_has(X86_FEATURE_HYPERVISOR)) {
return sprintf(buf, "%s; SMT Host state unknown\n",
mds_strings[mds_mitigation]);
}
@@ -1258,7 +1345,7 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr
break;
case X86_BUG_SPECTRE_V1:
- return sprintf(buf, "Mitigation: __user pointer sanitization\n");
+ return sprintf(buf, "%s\n", spectre_v1_strings[spectre_v1_mitigation]);
case X86_BUG_SPECTRE_V2:
return sprintf(buf, "%s%s%s%s%s%s\n", spectre_v2_strings[spectre_v2_enabled],
diff --git a/arch/x86/kernel/cpu/cacheinfo.c b/arch/x86/kernel/cpu/cacheinfo.c
index 0c5fcbd..9d863e8 100644
--- a/arch/x86/kernel/cpu/cacheinfo.c
+++ b/arch/x86/kernel/cpu/cacheinfo.c
@@ -651,8 +651,7 @@ void cacheinfo_amd_init_llc_id(struct cpuinfo_x86 *c, int cpu, u8 node_id)
if (c->x86 < 0x17) {
/* LLC is at the node level. */
per_cpu(cpu_llc_id, cpu) = node_id;
- } else if (c->x86 == 0x17 &&
- c->x86_model >= 0 && c->x86_model <= 0x1F) {
+ } else if (c->x86 == 0x17 && c->x86_model <= 0x1F) {
/*
* LLC is at the core complex level.
* Core complex ID is ApicId[3] for these processors.
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 1073118..b33fdfa 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -808,6 +808,30 @@ static void init_speculation_control(struct cpuinfo_x86 *c)
}
}
+static void init_cqm(struct cpuinfo_x86 *c)
+{
+ if (!cpu_has(c, X86_FEATURE_CQM_LLC)) {
+ c->x86_cache_max_rmid = -1;
+ c->x86_cache_occ_scale = -1;
+ return;
+ }
+
+ /* will be overridden if occupancy monitoring exists */
+ c->x86_cache_max_rmid = cpuid_ebx(0xf);
+
+ if (cpu_has(c, X86_FEATURE_CQM_OCCUP_LLC) ||
+ cpu_has(c, X86_FEATURE_CQM_MBM_TOTAL) ||
+ cpu_has(c, X86_FEATURE_CQM_MBM_LOCAL)) {
+ u32 eax, ebx, ecx, edx;
+
+ /* QoS sub-leaf, EAX=0Fh, ECX=1 */
+ cpuid_count(0xf, 1, &eax, &ebx, &ecx, &edx);
+
+ c->x86_cache_max_rmid = ecx;
+ c->x86_cache_occ_scale = ebx;
+ }
+}
+
void get_cpu_cap(struct cpuinfo_x86 *c)
{
u32 eax, ebx, ecx, edx;
@@ -839,33 +863,6 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
c->x86_capability[CPUID_D_1_EAX] = eax;
}
- /* Additional Intel-defined flags: level 0x0000000F */
- if (c->cpuid_level >= 0x0000000F) {
-
- /* QoS sub-leaf, EAX=0Fh, ECX=0 */
- cpuid_count(0x0000000F, 0, &eax, &ebx, &ecx, &edx);
- c->x86_capability[CPUID_F_0_EDX] = edx;
-
- if (cpu_has(c, X86_FEATURE_CQM_LLC)) {
- /* will be overridden if occupancy monitoring exists */
- c->x86_cache_max_rmid = ebx;
-
- /* QoS sub-leaf, EAX=0Fh, ECX=1 */
- cpuid_count(0x0000000F, 1, &eax, &ebx, &ecx, &edx);
- c->x86_capability[CPUID_F_1_EDX] = edx;
-
- if ((cpu_has(c, X86_FEATURE_CQM_OCCUP_LLC)) ||
- ((cpu_has(c, X86_FEATURE_CQM_MBM_TOTAL)) ||
- (cpu_has(c, X86_FEATURE_CQM_MBM_LOCAL)))) {
- c->x86_cache_max_rmid = ecx;
- c->x86_cache_occ_scale = ebx;
- }
- } else {
- c->x86_cache_max_rmid = -1;
- c->x86_cache_occ_scale = -1;
- }
- }
-
/* AMD-defined flags: level 0x80000001 */
eax = cpuid_eax(0x80000000);
c->extended_cpuid_level = eax;
@@ -896,6 +893,7 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
init_scattered_cpuid_features(c);
init_speculation_control(c);
+ init_cqm(c);
/*
* Clear/Set all flags overridden by options, after probe.
@@ -954,6 +952,7 @@ static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c)
#define NO_L1TF BIT(3)
#define NO_MDS BIT(4)
#define MSBDS_ONLY BIT(5)
+#define NO_SWAPGS BIT(6)
#define VULNWL(_vendor, _family, _model, _whitelist) \
{ X86_VENDOR_##_vendor, _family, _model, X86_FEATURE_ANY, _whitelist }
@@ -977,29 +976,37 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = {
VULNWL_INTEL(ATOM_BONNELL, NO_SPECULATION),
VULNWL_INTEL(ATOM_BONNELL_MID, NO_SPECULATION),
- VULNWL_INTEL(ATOM_SILVERMONT, NO_SSB | NO_L1TF | MSBDS_ONLY),
- VULNWL_INTEL(ATOM_SILVERMONT_X, NO_SSB | NO_L1TF | MSBDS_ONLY),
- VULNWL_INTEL(ATOM_SILVERMONT_MID, NO_SSB | NO_L1TF | MSBDS_ONLY),
- VULNWL_INTEL(ATOM_AIRMONT, NO_SSB | NO_L1TF | MSBDS_ONLY),
- VULNWL_INTEL(XEON_PHI_KNL, NO_SSB | NO_L1TF | MSBDS_ONLY),
- VULNWL_INTEL(XEON_PHI_KNM, NO_SSB | NO_L1TF | MSBDS_ONLY),
+ VULNWL_INTEL(ATOM_SILVERMONT, NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS),
+ VULNWL_INTEL(ATOM_SILVERMONT_X, NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS),
+ VULNWL_INTEL(ATOM_SILVERMONT_MID, NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS),
+ VULNWL_INTEL(ATOM_AIRMONT, NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS),
+ VULNWL_INTEL(XEON_PHI_KNL, NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS),
+ VULNWL_INTEL(XEON_PHI_KNM, NO_SSB | NO_L1TF | MSBDS_ONLY | NO_SWAPGS),
VULNWL_INTEL(CORE_YONAH, NO_SSB),
- VULNWL_INTEL(ATOM_AIRMONT_MID, NO_L1TF | MSBDS_ONLY),
+ VULNWL_INTEL(ATOM_AIRMONT_MID, NO_L1TF | MSBDS_ONLY | NO_SWAPGS),
- VULNWL_INTEL(ATOM_GOLDMONT, NO_MDS | NO_L1TF),
- VULNWL_INTEL(ATOM_GOLDMONT_X, NO_MDS | NO_L1TF),
- VULNWL_INTEL(ATOM_GOLDMONT_PLUS, NO_MDS | NO_L1TF),
+ VULNWL_INTEL(ATOM_GOLDMONT, NO_MDS | NO_L1TF | NO_SWAPGS),
+ VULNWL_INTEL(ATOM_GOLDMONT_X, NO_MDS | NO_L1TF | NO_SWAPGS),
+ VULNWL_INTEL(ATOM_GOLDMONT_PLUS, NO_MDS | NO_L1TF | NO_SWAPGS),
+
+ /*
+ * Technically, swapgs isn't serializing on AMD (despite it previously
+ * being documented as such in the APM). But according to AMD, %gs is
+ * updated non-speculatively, and the issuing of %gs-relative memory
+ * operands will be blocked until the %gs update completes, which is
+ * good enough for our purposes.
+ */
/* AMD Family 0xf - 0x12 */
- VULNWL_AMD(0x0f, NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS),
- VULNWL_AMD(0x10, NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS),
- VULNWL_AMD(0x11, NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS),
- VULNWL_AMD(0x12, NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS),
+ VULNWL_AMD(0x0f, NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS),
+ VULNWL_AMD(0x10, NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS),
+ VULNWL_AMD(0x11, NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS),
+ VULNWL_AMD(0x12, NO_MELTDOWN | NO_SSB | NO_L1TF | NO_MDS | NO_SWAPGS),
/* FAMILY_ANY must be last, otherwise 0x0f - 0x12 matches won't work */
- VULNWL_AMD(X86_FAMILY_ANY, NO_MELTDOWN | NO_L1TF | NO_MDS),
+ VULNWL_AMD(X86_FAMILY_ANY, NO_MELTDOWN | NO_L1TF | NO_MDS | NO_SWAPGS),
{}
};
@@ -1036,6 +1043,9 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
setup_force_cpu_bug(X86_BUG_MSBDS_ONLY);
}
+ if (!cpu_matches(NO_SWAPGS))
+ setup_force_cpu_bug(X86_BUG_SWAPGS);
+
if (cpu_matches(NO_MELTDOWN))
return;
diff --git a/arch/x86/kernel/cpu/cpuid-deps.c b/arch/x86/kernel/cpu/cpuid-deps.c
index 2c0bd38..fa07a22 100644
--- a/arch/x86/kernel/cpu/cpuid-deps.c
+++ b/arch/x86/kernel/cpu/cpuid-deps.c
@@ -59,6 +59,9 @@ static const struct cpuid_dep cpuid_deps[] = {
{ X86_FEATURE_AVX512_4VNNIW, X86_FEATURE_AVX512F },
{ X86_FEATURE_AVX512_4FMAPS, X86_FEATURE_AVX512F },
{ X86_FEATURE_AVX512_VPOPCNTDQ, X86_FEATURE_AVX512F },
+ { X86_FEATURE_CQM_OCCUP_LLC, X86_FEATURE_CQM_LLC },
+ { X86_FEATURE_CQM_MBM_TOTAL, X86_FEATURE_CQM_LLC },
+ { X86_FEATURE_CQM_MBM_LOCAL, X86_FEATURE_CQM_LLC },
{}
};
diff --git a/arch/x86/kernel/cpu/mkcapflags.sh b/arch/x86/kernel/cpu/mkcapflags.sh
index d0dfb89..aed45b8 100644
--- a/arch/x86/kernel/cpu/mkcapflags.sh
+++ b/arch/x86/kernel/cpu/mkcapflags.sh
@@ -4,6 +4,8 @@
# Generate the x86_cap/bug_flags[] arrays from include/asm/cpufeatures.h
#
+set -e
+
IN=$1
OUT=$2
diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c
index 772c219..5a52672 100644
--- a/arch/x86/kernel/cpu/scattered.c
+++ b/arch/x86/kernel/cpu/scattered.c
@@ -21,6 +21,10 @@ struct cpuid_bit {
static const struct cpuid_bit cpuid_bits[] = {
{ X86_FEATURE_APERFMPERF, CPUID_ECX, 0, 0x00000006, 0 },
{ X86_FEATURE_EPB, CPUID_ECX, 3, 0x00000006, 0 },
+ { X86_FEATURE_CQM_LLC, CPUID_EDX, 1, 0x0000000f, 0 },
+ { X86_FEATURE_CQM_OCCUP_LLC, CPUID_EDX, 0, 0x0000000f, 1 },
+ { X86_FEATURE_CQM_MBM_TOTAL, CPUID_EDX, 1, 0x0000000f, 1 },
+ { X86_FEATURE_CQM_MBM_LOCAL, CPUID_EDX, 2, 0x0000000f, 1 },
{ X86_FEATURE_CAT_L3, CPUID_EBX, 1, 0x00000010, 0 },
{ X86_FEATURE_CAT_L2, CPUID_EBX, 2, 0x00000010, 0 },
{ X86_FEATURE_CDP_L3, CPUID_ECX, 2, 0x00000010, 1 },
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index ddee1f0..250cfa8 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -184,24 +184,25 @@ unsigned long __head __startup_64(unsigned long physaddr,
pgtable_flags = _KERNPG_TABLE_NOENC + sme_get_me_mask();
if (la57) {
- p4d = fixup_pointer(early_dynamic_pgts[next_early_pgt++], physaddr);
+ p4d = fixup_pointer(early_dynamic_pgts[(*next_pgt_ptr)++],
+ physaddr);
i = (physaddr >> PGDIR_SHIFT) % PTRS_PER_PGD;
pgd[i + 0] = (pgdval_t)p4d + pgtable_flags;
pgd[i + 1] = (pgdval_t)p4d + pgtable_flags;
- i = (physaddr >> P4D_SHIFT) % PTRS_PER_P4D;
- p4d[i + 0] = (pgdval_t)pud + pgtable_flags;
- p4d[i + 1] = (pgdval_t)pud + pgtable_flags;
+ i = physaddr >> P4D_SHIFT;
+ p4d[(i + 0) % PTRS_PER_P4D] = (pgdval_t)pud + pgtable_flags;
+ p4d[(i + 1) % PTRS_PER_P4D] = (pgdval_t)pud + pgtable_flags;
} else {
i = (physaddr >> PGDIR_SHIFT) % PTRS_PER_PGD;
pgd[i + 0] = (pgdval_t)pud + pgtable_flags;
pgd[i + 1] = (pgdval_t)pud + pgtable_flags;
}
- i = (physaddr >> PUD_SHIFT) % PTRS_PER_PUD;
- pud[i + 0] = (pudval_t)pmd + pgtable_flags;
- pud[i + 1] = (pudval_t)pmd + pgtable_flags;
+ i = physaddr >> PUD_SHIFT;
+ pud[(i + 0) % PTRS_PER_PUD] = (pudval_t)pmd + pgtable_flags;
+ pud[(i + 1) % PTRS_PER_PUD] = (pudval_t)pmd + pgtable_flags;
pmd_entry = __PAGE_KERNEL_LARGE_EXEC & ~_PAGE_GLOBAL;
/* Filter out unsupported __PAGE_KERNEL_* bits: */
@@ -211,8 +212,9 @@ unsigned long __head __startup_64(unsigned long physaddr,
pmd_entry += physaddr;
for (i = 0; i < DIV_ROUND_UP(_end - _text, PMD_SIZE); i++) {
- int idx = i + (physaddr >> PMD_SHIFT) % PTRS_PER_PMD;
- pmd[idx] = pmd_entry + i * PMD_SIZE;
+ int idx = i + (physaddr >> PMD_SHIFT);
+
+ pmd[idx % PTRS_PER_PMD] = pmd_entry + i * PMD_SIZE;
}
/*
diff --git a/arch/x86/kernel/idt.c b/arch/x86/kernel/idt.c
index 01adea2..a7e0e97 100644
--- a/arch/x86/kernel/idt.c
+++ b/arch/x86/kernel/idt.c
@@ -321,7 +321,8 @@ void __init idt_setup_apic_and_irq_gates(void)
#ifdef CONFIG_X86_LOCAL_APIC
for_each_clear_bit_from(i, system_vectors, NR_VECTORS) {
set_bit(i, system_vectors);
- set_intr_gate(i, spurious_interrupt);
+ entry = spurious_entries_start + 8 * (i - FIRST_SYSTEM_VECTOR);
+ set_intr_gate(i, entry);
}
#endif
}
diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c
index 59b5f2e..a975246 100644
--- a/arch/x86/kernel/irq.c
+++ b/arch/x86/kernel/irq.c
@@ -246,7 +246,7 @@ __visible unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
if (!handle_irq(desc, regs)) {
ack_APIC_irq();
- if (desc != VECTOR_RETRIGGERED) {
+ if (desc != VECTOR_RETRIGGERED && desc != VECTOR_SHUTDOWN) {
pr_emerg_ratelimited("%s: %d.%d No irq handler for vector\n",
__func__, smp_processor_id(),
vector);
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index 7f89d60..cee45d4 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -830,6 +830,7 @@ asm(
"cmpb $0, " __stringify(KVM_STEAL_TIME_preempted) "+steal_time(%rax);"
"setne %al;"
"ret;"
+".size __raw_callee_save___kvm_vcpu_is_preempted, .-__raw_callee_save___kvm_vcpu_is_preempted;"
".popsection");
#endif
diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c
index ddb1ca6..5b4c327 100644
--- a/arch/x86/kernel/mpparse.c
+++ b/arch/x86/kernel/mpparse.c
@@ -547,17 +547,15 @@ void __init default_get_smp_config(unsigned int early)
* local APIC has default address
*/
mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
- return;
+ goto out;
}
pr_info("Default MP configuration #%d\n", mpf->feature1);
construct_default_ISA_mptable(mpf->feature1);
} else if (mpf->physptr) {
- if (check_physptr(mpf, early)) {
- early_memunmap(mpf, sizeof(*mpf));
- return;
- }
+ if (check_physptr(mpf, early))
+ goto out;
} else
BUG();
@@ -566,7 +564,7 @@ void __init default_get_smp_config(unsigned int early)
/*
* Only use the first configuration found.
*/
-
+out:
early_memunmap(mpf, sizeof(*mpf));
}
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index e2ee403..aeba778 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -24,6 +24,7 @@
#include <linux/rcupdate.h>
#include <linux/export.h>
#include <linux/context_tracking.h>
+#include <linux/nospec.h>
#include <linux/uaccess.h>
#include <asm/pgtable.h>
@@ -651,9 +652,11 @@ static unsigned long ptrace_get_debugreg(struct task_struct *tsk, int n)
{
struct thread_struct *thread = &tsk->thread;
unsigned long val = 0;
+ int index = n;
if (n < HBP_NUM) {
- struct perf_event *bp = thread->ptrace_bps[n];
+ struct perf_event *bp = thread->ptrace_bps[index];
+ index = array_index_nospec(index, HBP_NUM);
if (bp)
val = bp->hw.info.address;
diff --git a/arch/x86/kernel/sysfb_efi.c b/arch/x86/kernel/sysfb_efi.c
index 623965e..897da52 100644
--- a/arch/x86/kernel/sysfb_efi.c
+++ b/arch/x86/kernel/sysfb_efi.c
@@ -231,9 +231,55 @@ static const struct dmi_system_id efifb_dmi_system_table[] __initconst = {
{},
};
+/*
+ * Some devices have a portrait LCD but advertise a landscape resolution (and
+ * pitch). We simply swap width and height for these devices so that we can
+ * correctly deal with some of them coming with multiple resolutions.
+ */
+static const struct dmi_system_id efifb_dmi_swap_width_height[] __initconst = {
+ {
+ /*
+ * Lenovo MIIX310-10ICR, only some batches have the troublesome
+ * 800x1280 portrait screen. Luckily the portrait version has
+ * its own BIOS version, so we match on that.
+ */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "MIIX 310-10ICR"),
+ DMI_EXACT_MATCH(DMI_BIOS_VERSION, "1HCN44WW"),
+ },
+ },
+ {
+ /* Lenovo MIIX 320-10ICR with 800x1280 portrait screen */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION,
+ "Lenovo MIIX 320-10ICR"),
+ },
+ },
+ {
+ /* Lenovo D330 with 800x1280 or 1200x1920 portrait screen */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION,
+ "Lenovo ideapad D330-10IGM"),
+ },
+ },
+ {},
+};
+
__init void sysfb_apply_efi_quirks(void)
{
if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI ||
!(screen_info.capabilities & VIDEO_CAPABILITY_SKIP_QUIRKS))
dmi_check_system(efifb_dmi_system_table);
+
+ if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI &&
+ dmi_check_system(efifb_dmi_swap_width_height)) {
+ u16 temp = screen_info.lfb_width;
+
+ screen_info.lfb_width = screen_info.lfb_height;
+ screen_info.lfb_height = temp;
+ screen_info.lfb_linelength = 4 * screen_info.lfb_width;
+ }
}
diff --git a/arch/x86/kernel/tls.c b/arch/x86/kernel/tls.c
index a5b802a..71d3fef 100644
--- a/arch/x86/kernel/tls.c
+++ b/arch/x86/kernel/tls.c
@@ -5,6 +5,7 @@
#include <linux/user.h>
#include <linux/regset.h>
#include <linux/syscalls.h>
+#include <linux/nospec.h>
#include <linux/uaccess.h>
#include <asm/desc.h>
@@ -220,6 +221,7 @@ int do_get_thread_area(struct task_struct *p, int idx,
struct user_desc __user *u_info)
{
struct user_desc info;
+ int index;
if (idx == -1 && get_user(idx, &u_info->entry_number))
return -EFAULT;
@@ -227,8 +229,11 @@ int do_get_thread_area(struct task_struct *p, int idx,
if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
return -EINVAL;
- fill_user_desc(&info, idx,
- &p->thread.tls_array[idx - GDT_ENTRY_TLS_MIN]);
+ index = idx - GDT_ENTRY_TLS_MIN;
+ index = array_index_nospec(index,
+ GDT_ENTRY_TLS_MAX - GDT_ENTRY_TLS_MIN + 1);
+
+ fill_user_desc(&info, idx, &p->thread.tls_array[index]);
if (copy_to_user(u_info, &info, sizeof(info)))
return -EFAULT;
diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h
index 9a327d5..d78a614 100644
--- a/arch/x86/kvm/cpuid.h
+++ b/arch/x86/kvm/cpuid.h
@@ -47,8 +47,6 @@ static const struct cpuid_reg reverse_cpuid[] = {
[CPUID_8000_0001_ECX] = {0x80000001, 0, CPUID_ECX},
[CPUID_7_0_EBX] = { 7, 0, CPUID_EBX},
[CPUID_D_1_EAX] = { 0xd, 1, CPUID_EAX},
- [CPUID_F_0_EDX] = { 0xf, 0, CPUID_EDX},
- [CPUID_F_1_EDX] = { 0xf, 1, CPUID_EDX},
[CPUID_8000_0008_EBX] = {0x80000008, 0, CPUID_EBX},
[CPUID_6_EAX] = { 6, 0, CPUID_EAX},
[CPUID_8000_000A_EDX] = {0x8000000a, 0, CPUID_EDX},
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index e0f982e..cdc0c46 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -4532,11 +4532,11 @@ static void update_permission_bitmask(struct kvm_vcpu *vcpu,
*/
/* Faults from writes to non-writable pages */
- u8 wf = (pfec & PFERR_WRITE_MASK) ? ~w : 0;
+ u8 wf = (pfec & PFERR_WRITE_MASK) ? (u8)~w : 0;
/* Faults from user mode accesses to supervisor pages */
- u8 uf = (pfec & PFERR_USER_MASK) ? ~u : 0;
+ u8 uf = (pfec & PFERR_USER_MASK) ? (u8)~u : 0;
/* Faults from fetches of non-executable pages*/
- u8 ff = (pfec & PFERR_FETCH_MASK) ? ~x : 0;
+ u8 ff = (pfec & PFERR_FETCH_MASK) ? (u8)~x : 0;
/* Faults from kernel mode fetches of user pages */
u8 smepf = 0;
/* Faults from kernel mode accesses of user pages */
diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index 952aebd..acc8d21 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -131,8 +131,8 @@ static void pmc_reprogram_counter(struct kvm_pmc *pmc, u32 type,
intr ? kvm_perf_overflow_intr :
kvm_perf_overflow, pmc);
if (IS_ERR(event)) {
- printk_once("kvm_pmu: event creation failed %ld\n",
- PTR_ERR(event));
+ pr_debug_ratelimited("kvm_pmu: event creation failed %ld for pmc->idx = %d\n",
+ PTR_ERR(event), pmc->idx);
return;
}
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 73d6d58..4cf16378 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -8457,6 +8457,7 @@ static void vmx_disable_shadow_vmcs(struct vcpu_vmx *vmx)
{
vmcs_clear_bits(SECONDARY_VM_EXEC_CONTROL, SECONDARY_EXEC_SHADOW_VMCS);
vmcs_write64(VMCS_LINK_POINTER, -1ull);
+ vmx->nested.sync_shadow_vmcs = false;
}
static inline void nested_release_vmcs12(struct vcpu_vmx *vmx)
@@ -8468,7 +8469,6 @@ static inline void nested_release_vmcs12(struct vcpu_vmx *vmx)
/* copy to memory all shadowed fields in case
they were modified */
copy_shadow_to_vmcs12(vmx);
- vmx->nested.sync_shadow_vmcs = false;
vmx_disable_shadow_vmcs(vmx);
}
vmx->nested.posted_intr_nv = -1;
@@ -8490,6 +8490,8 @@ static void free_nested(struct vcpu_vmx *vmx)
if (!vmx->nested.vmxon && !vmx->nested.smm.vmxon)
return;
+ kvm_clear_request(KVM_REQ_GET_VMCS12_PAGES, &vmx->vcpu);
+
hrtimer_cancel(&vmx->nested.preemption_timer);
vmx->nested.vmxon = false;
vmx->nested.smm.vmxon = false;
@@ -8668,6 +8670,9 @@ static void copy_shadow_to_vmcs12(struct vcpu_vmx *vmx)
u64 field_value;
struct vmcs *shadow_vmcs = vmx->vmcs01.shadow_vmcs;
+ if (WARN_ON(!shadow_vmcs))
+ return;
+
preempt_disable();
vmcs_load(shadow_vmcs);
@@ -8706,6 +8711,9 @@ static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx)
u64 field_value = 0;
struct vmcs *shadow_vmcs = vmx->vmcs01.shadow_vmcs;
+ if (WARN_ON(!shadow_vmcs))
+ return;
+
vmcs_load(shadow_vmcs);
for (q = 0; q < ARRAY_SIZE(fields); q++) {
diff --git a/arch/x86/math-emu/fpu_emu.h b/arch/x86/math-emu/fpu_emu.h
index a5a41ec..0c12222 100644
--- a/arch/x86/math-emu/fpu_emu.h
+++ b/arch/x86/math-emu/fpu_emu.h
@@ -177,7 +177,7 @@ static inline void reg_copy(FPU_REG const *x, FPU_REG *y)
#define setexponentpos(x,y) { (*(short *)&((x)->exp)) = \
((y) + EXTENDED_Ebias) & 0x7fff; }
#define exponent16(x) (*(short *)&((x)->exp))
-#define setexponent16(x,y) { (*(short *)&((x)->exp)) = (y); }
+#define setexponent16(x,y) { (*(short *)&((x)->exp)) = (u16)(y); }
#define addexponent(x,y) { (*(short *)&((x)->exp)) += (y); }
#define stdexp(x) { (*(short *)&((x)->exp)) += EXTENDED_Ebias; }
diff --git a/arch/x86/math-emu/reg_constant.c b/arch/x86/math-emu/reg_constant.c
index 8dc9095..742619e 100644
--- a/arch/x86/math-emu/reg_constant.c
+++ b/arch/x86/math-emu/reg_constant.c
@@ -18,7 +18,7 @@
#include "control_w.h"
#define MAKE_REG(s, e, l, h) { l, h, \
- ((EXTENDED_Ebias+(e)) | ((SIGN_##s != 0)*0x8000)) }
+ (u16)((EXTENDED_Ebias+(e)) | ((SIGN_##s != 0)*0x8000)) }
FPU_REG const CONST_1 = MAKE_REG(POS, 0, 0x00000000, 0x80000000);
#if 0
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index 2580cd2..a32fc3d 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -190,9 +190,7 @@ struct jit_context {
#define BPF_MAX_INSN_SIZE 128
#define BPF_INSN_SAFETY 64
-#define AUX_STACK_SPACE 40 /* Space for RBX, R13, R14, R15, tailcnt */
-
-#define PROLOGUE_SIZE 37
+#define PROLOGUE_SIZE 20
/*
* Emit x86-64 prologue code for BPF program and check its size.
@@ -203,44 +201,19 @@ static void emit_prologue(u8 **pprog, u32 stack_depth, bool ebpf_from_cbpf)
u8 *prog = *pprog;
int cnt = 0;
- /* push rbp */
- EMIT1(0x55);
-
- /* mov rbp,rsp */
- EMIT3(0x48, 0x89, 0xE5);
-
- /* sub rsp, rounded_stack_depth + AUX_STACK_SPACE */
- EMIT3_off32(0x48, 0x81, 0xEC,
- round_up(stack_depth, 8) + AUX_STACK_SPACE);
-
- /* sub rbp, AUX_STACK_SPACE */
- EMIT4(0x48, 0x83, 0xED, AUX_STACK_SPACE);
-
- /* mov qword ptr [rbp+0],rbx */
- EMIT4(0x48, 0x89, 0x5D, 0);
- /* mov qword ptr [rbp+8],r13 */
- EMIT4(0x4C, 0x89, 0x6D, 8);
- /* mov qword ptr [rbp+16],r14 */
- EMIT4(0x4C, 0x89, 0x75, 16);
- /* mov qword ptr [rbp+24],r15 */
- EMIT4(0x4C, 0x89, 0x7D, 24);
-
+ EMIT1(0x55); /* push rbp */
+ EMIT3(0x48, 0x89, 0xE5); /* mov rbp, rsp */
+ /* sub rsp, rounded_stack_depth */
+ EMIT3_off32(0x48, 0x81, 0xEC, round_up(stack_depth, 8));
+ EMIT1(0x53); /* push rbx */
+ EMIT2(0x41, 0x55); /* push r13 */
+ EMIT2(0x41, 0x56); /* push r14 */
+ EMIT2(0x41, 0x57); /* push r15 */
if (!ebpf_from_cbpf) {
- /*
- * Clear the tail call counter (tail_call_cnt): for eBPF tail
- * calls we need to reset the counter to 0. It's done in two
- * instructions, resetting RAX register to 0, and moving it
- * to the counter location.
- */
-
- /* xor eax, eax */
- EMIT2(0x31, 0xc0);
- /* mov qword ptr [rbp+32], rax */
- EMIT4(0x48, 0x89, 0x45, 32);
-
+ /* zero init tail_call_cnt */
+ EMIT2(0x6a, 0x00);
BUILD_BUG_ON(cnt != PROLOGUE_SIZE);
}
-
*pprog = prog;
}
@@ -285,13 +258,13 @@ static void emit_bpf_tail_call(u8 **pprog)
* if (tail_call_cnt > MAX_TAIL_CALL_CNT)
* goto out;
*/
- EMIT2_off32(0x8B, 0x85, 36); /* mov eax, dword ptr [rbp + 36] */
+ EMIT2_off32(0x8B, 0x85, -36 - MAX_BPF_STACK); /* mov eax, dword ptr [rbp - 548] */
EMIT3(0x83, 0xF8, MAX_TAIL_CALL_CNT); /* cmp eax, MAX_TAIL_CALL_CNT */
#define OFFSET2 (30 + RETPOLINE_RAX_BPF_JIT_SIZE)
EMIT2(X86_JA, OFFSET2); /* ja out */
label2 = cnt;
EMIT3(0x83, 0xC0, 0x01); /* add eax, 1 */
- EMIT2_off32(0x89, 0x85, 36); /* mov dword ptr [rbp + 36], eax */
+ EMIT2_off32(0x89, 0x85, -36 - MAX_BPF_STACK); /* mov dword ptr [rbp -548], eax */
/* prog = array->ptrs[index]; */
EMIT4_off32(0x48, 0x8B, 0x84, 0xD6, /* mov rax, [rsi + rdx * 8 + offsetof(...)] */
@@ -1006,19 +979,14 @@ xadd: if (is_imm8(insn->off))
seen_exit = true;
/* Update cleanup_addr */
ctx->cleanup_addr = proglen;
- /* mov rbx, qword ptr [rbp+0] */
- EMIT4(0x48, 0x8B, 0x5D, 0);
- /* mov r13, qword ptr [rbp+8] */
- EMIT4(0x4C, 0x8B, 0x6D, 8);
- /* mov r14, qword ptr [rbp+16] */
- EMIT4(0x4C, 0x8B, 0x75, 16);
- /* mov r15, qword ptr [rbp+24] */
- EMIT4(0x4C, 0x8B, 0x7D, 24);
-
- /* add rbp, AUX_STACK_SPACE */
- EMIT4(0x48, 0x83, 0xC5, AUX_STACK_SPACE);
- EMIT1(0xC9); /* leave */
- EMIT1(0xC3); /* ret */
+ if (!bpf_prog_was_classic(bpf_prog))
+ EMIT1(0x5B); /* get rid of tail_call_cnt */
+ EMIT2(0x41, 0x5F); /* pop r15 */
+ EMIT2(0x41, 0x5E); /* pop r14 */
+ EMIT2(0x41, 0x5D); /* pop r13 */
+ EMIT1(0x5B); /* pop rbx */
+ EMIT1(0xC9); /* leave */
+ EMIT1(0xC3); /* ret */
break;
default:
diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c
index 782f98b..1730a26 100644
--- a/arch/x86/xen/enlighten_pv.c
+++ b/arch/x86/xen/enlighten_pv.c
@@ -597,12 +597,12 @@ struct trap_array_entry {
static struct trap_array_entry trap_array[] = {
{ debug, xen_xendebug, true },
- { int3, xen_xenint3, true },
{ double_fault, xen_double_fault, true },
#ifdef CONFIG_X86_MCE
{ machine_check, xen_machine_check, true },
#endif
{ nmi, xen_xennmi, true },
+ { int3, xen_int3, false },
{ overflow, xen_overflow, false },
#ifdef CONFIG_IA32_EMULATION
{ entry_INT80_compat, xen_entry_INT80_compat, false },
diff --git a/arch/x86/xen/xen-asm_64.S b/arch/x86/xen/xen-asm_64.S
index 417b339..3a6feed 100644
--- a/arch/x86/xen/xen-asm_64.S
+++ b/arch/x86/xen/xen-asm_64.S
@@ -30,7 +30,6 @@
xen_pv_trap debug
xen_pv_trap xendebug
xen_pv_trap int3
-xen_pv_trap xenint3
xen_pv_trap xennmi
xen_pv_trap overflow
xen_pv_trap bounds
diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c
index 6bb3979..becd793 100644
--- a/block/bfq-iosched.c
+++ b/block/bfq-iosched.c
@@ -4116,6 +4116,7 @@ static void bfq_exit_icq_bfqq(struct bfq_io_cq *bic, bool is_sync)
unsigned long flags;
spin_lock_irqsave(&bfqd->lock, flags);
+ bfqq->bic = NULL;
bfq_exit_bfqq(bfqd, bfqq);
bic_set_bfqq(bic, NULL, is_sync);
spin_unlock_irqrestore(&bfqd->lock, flags);
diff --git a/block/bio-integrity.c b/block/bio-integrity.c
index 67b5fb8..5bd90cd 100644
--- a/block/bio-integrity.c
+++ b/block/bio-integrity.c
@@ -291,8 +291,12 @@ bool bio_integrity_prep(struct bio *bio)
ret = bio_integrity_add_page(bio, virt_to_page(buf),
bytes, offset);
- if (ret == 0)
- return false;
+ if (ret == 0) {
+ printk(KERN_ERR "could not attach integrity payload\n");
+ kfree(buf);
+ status = BLK_STS_RESOURCE;
+ goto err_end_io;
+ }
if (ret < bytes)
break;
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index c630e02..5275241 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -1016,8 +1016,12 @@ static int blkcg_print_stat(struct seq_file *sf, void *v)
}
next:
if (has_stats) {
- off += scnprintf(buf+off, size-off, "\n");
- seq_commit(sf, off);
+ if (off < size - 1) {
+ off += scnprintf(buf+off, size-off, "\n");
+ seq_commit(sf, off);
+ } else {
+ seq_commit(sf, -1);
+ }
}
}
diff --git a/block/blk-core.c b/block/blk-core.c
index 40ad6ea..365d17b 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -198,6 +198,7 @@ void blk_rq_init(struct request_queue *q, struct request *rq)
rq->internal_tag = -1;
rq->start_time_ns = ktime_get_ns();
rq->part = NULL;
+ refcount_set(&rq->ref, 1);
}
EXPORT_SYMBOL(blk_rq_init);
@@ -420,24 +421,25 @@ void blk_sync_queue(struct request_queue *q)
EXPORT_SYMBOL(blk_sync_queue);
/**
- * blk_set_preempt_only - set QUEUE_FLAG_PREEMPT_ONLY
+ * blk_set_pm_only - increment pm_only counter
* @q: request queue pointer
- *
- * Returns the previous value of the PREEMPT_ONLY flag - 0 if the flag was not
- * set and 1 if the flag was already set.
*/
-int blk_set_preempt_only(struct request_queue *q)
+void blk_set_pm_only(struct request_queue *q)
{
- return blk_queue_flag_test_and_set(QUEUE_FLAG_PREEMPT_ONLY, q);
+ atomic_inc(&q->pm_only);
}
-EXPORT_SYMBOL_GPL(blk_set_preempt_only);
+EXPORT_SYMBOL_GPL(blk_set_pm_only);
-void blk_clear_preempt_only(struct request_queue *q)
+void blk_clear_pm_only(struct request_queue *q)
{
- blk_queue_flag_clear(QUEUE_FLAG_PREEMPT_ONLY, q);
- wake_up_all(&q->mq_freeze_wq);
+ int pm_only;
+
+ pm_only = atomic_dec_return(&q->pm_only);
+ WARN_ON_ONCE(pm_only < 0);
+ if (pm_only == 0)
+ wake_up_all(&q->mq_freeze_wq);
}
-EXPORT_SYMBOL_GPL(blk_clear_preempt_only);
+EXPORT_SYMBOL_GPL(blk_clear_pm_only);
/**
* __blk_run_queue_uncond - run a queue whether or not it has been stopped
@@ -915,7 +917,7 @@ EXPORT_SYMBOL(blk_alloc_queue);
*/
int blk_queue_enter(struct request_queue *q, blk_mq_req_flags_t flags)
{
- const bool preempt = flags & BLK_MQ_REQ_PREEMPT;
+ const bool pm = flags & BLK_MQ_REQ_PREEMPT;
while (true) {
bool success = false;
@@ -923,11 +925,11 @@ int blk_queue_enter(struct request_queue *q, blk_mq_req_flags_t flags)
rcu_read_lock();
if (percpu_ref_tryget_live(&q->q_usage_counter)) {
/*
- * The code that sets the PREEMPT_ONLY flag is
- * responsible for ensuring that that flag is globally
- * visible before the queue is unfrozen.
+ * The code that increments the pm_only counter is
+ * responsible for ensuring that that counter is
+ * globally visible before the queue is unfrozen.
*/
- if (preempt || !blk_queue_preempt_only(q)) {
+ if (pm || !blk_queue_pm_only(q)) {
success = true;
} else {
percpu_ref_put(&q->q_usage_counter);
@@ -952,7 +954,7 @@ int blk_queue_enter(struct request_queue *q, blk_mq_req_flags_t flags)
wait_event(q->mq_freeze_wq,
(atomic_read(&q->mq_freeze_depth) == 0 &&
- (preempt || !blk_queue_preempt_only(q))) ||
+ (pm || !blk_queue_pm_only(q))) ||
blk_queue_dying(q));
if (blk_queue_dying(q))
return -ENODEV;
diff --git a/block/blk-iolatency.c b/block/blk-iolatency.c
index da42cb5..9b6a150 100644
--- a/block/blk-iolatency.c
+++ b/block/blk-iolatency.c
@@ -567,6 +567,10 @@ static void blkcg_iolatency_done_bio(struct rq_qos *rqos, struct bio *bio)
if (!blkg)
return;
+ /* We didn't actually submit this bio, don't account it. */
+ if (bio->bi_status == BLK_STS_AGAIN)
+ return;
+
iolat = blkg_to_lat(bio->bi_blkg);
if (!iolat)
return;
@@ -744,8 +748,10 @@ static int iolatency_set_min_lat_nsec(struct blkcg_gq *blkg, u64 val)
if (!oldval && val)
return 1;
- if (oldval && !val)
+ if (oldval && !val) {
+ blkcg_clear_delay(blkg);
return -1;
+ }
return 0;
}
diff --git a/block/blk-mq-debugfs.c b/block/blk-mq-debugfs.c
index cb1e6cf..a5ea868 100644
--- a/block/blk-mq-debugfs.c
+++ b/block/blk-mq-debugfs.c
@@ -102,6 +102,14 @@ static int blk_flags_show(struct seq_file *m, const unsigned long flags,
return 0;
}
+static int queue_pm_only_show(void *data, struct seq_file *m)
+{
+ struct request_queue *q = data;
+
+ seq_printf(m, "%d\n", atomic_read(&q->pm_only));
+ return 0;
+}
+
#define QUEUE_FLAG_NAME(name) [QUEUE_FLAG_##name] = #name
static const char *const blk_queue_flag_name[] = {
QUEUE_FLAG_NAME(QUEUED),
@@ -132,7 +140,6 @@ static const char *const blk_queue_flag_name[] = {
QUEUE_FLAG_NAME(REGISTERED),
QUEUE_FLAG_NAME(SCSI_PASSTHROUGH),
QUEUE_FLAG_NAME(QUIESCED),
- QUEUE_FLAG_NAME(PREEMPT_ONLY),
};
#undef QUEUE_FLAG_NAME
@@ -209,6 +216,7 @@ static ssize_t queue_write_hint_store(void *data, const char __user *buf,
static const struct blk_mq_debugfs_attr blk_mq_debugfs_queue_attrs[] = {
{ "poll_stat", 0400, queue_poll_stat_show },
{ "requeue_list", 0400, .seq_ops = &queue_requeue_list_seq_ops },
+ { "pm_only", 0600, queue_pm_only_show, NULL },
{ "state", 0600, queue_state_show, queue_state_write },
{ "write_hints", 0600, queue_write_hint_show, queue_write_hint_store },
{ "zone_wlock", 0400, queue_zone_wlock_show, NULL },
diff --git a/block/blk-throttle.c b/block/blk-throttle.c
index 01d0620..caee658 100644
--- a/block/blk-throttle.c
+++ b/block/blk-throttle.c
@@ -892,13 +892,10 @@ static bool tg_with_in_iops_limit(struct throtl_grp *tg, struct bio *bio,
unsigned long jiffy_elapsed, jiffy_wait, jiffy_elapsed_rnd;
u64 tmp;
- jiffy_elapsed = jiffy_elapsed_rnd = jiffies - tg->slice_start[rw];
+ jiffy_elapsed = jiffies - tg->slice_start[rw];
- /* Slice has just started. Consider one slice interval */
- if (!jiffy_elapsed)
- jiffy_elapsed_rnd = tg->td->throtl_slice;
-
- jiffy_elapsed_rnd = roundup(jiffy_elapsed_rnd, tg->td->throtl_slice);
+ /* Round up to the next throttle slice, wait time must be nonzero */
+ jiffy_elapsed_rnd = roundup(jiffy_elapsed + 1, tg->td->throtl_slice);
/*
* jiffy_elapsed_rnd should not be a big value as minimum iops can be
diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
index f3702e5..d8a73d9 100644
--- a/crypto/asymmetric_keys/Kconfig
+++ b/crypto/asymmetric_keys/Kconfig
@@ -15,6 +15,7 @@
select MPILIB
select CRYPTO_HASH_INFO
select CRYPTO_AKCIPHER
+ select CRYPTO_HASH
help
This option provides support for asymmetric public key type handling.
If signature generation and/or verification are to be used,
@@ -34,6 +35,7 @@
config PKCS7_MESSAGE_PARSER
tristate "PKCS#7 message parser"
depends on X509_CERTIFICATE_PARSER
+ select CRYPTO_HASH
select ASN1
select OID_REGISTRY
help
@@ -56,6 +58,7 @@
bool "Support for PE file signature verification"
depends on PKCS7_MESSAGE_PARSER=y
depends on SYSTEM_DATA_VERIFICATION
+ select CRYPTO_HASH
select ASN1
select OID_REGISTRY
help
diff --git a/crypto/chacha20poly1305.c b/crypto/chacha20poly1305.c
index f2b1588..dce194c 100644
--- a/crypto/chacha20poly1305.c
+++ b/crypto/chacha20poly1305.c
@@ -67,6 +67,8 @@ struct chachapoly_req_ctx {
unsigned int cryptlen;
/* Actual AD, excluding IV */
unsigned int assoclen;
+ /* request flags, with MAY_SLEEP cleared if needed */
+ u32 flags;
union {
struct poly_req poly;
struct chacha_req chacha;
@@ -76,8 +78,12 @@ struct chachapoly_req_ctx {
static inline void async_done_continue(struct aead_request *req, int err,
int (*cont)(struct aead_request *))
{
- if (!err)
+ if (!err) {
+ struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
+
+ rctx->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
err = cont(req);
+ }
if (err != -EINPROGRESS && err != -EBUSY)
aead_request_complete(req, err);
@@ -144,7 +150,7 @@ static int chacha_decrypt(struct aead_request *req)
dst = scatterwalk_ffwd(rctx->dst, req->dst, req->assoclen);
}
- skcipher_request_set_callback(&creq->req, aead_request_flags(req),
+ skcipher_request_set_callback(&creq->req, rctx->flags,
chacha_decrypt_done, req);
skcipher_request_set_tfm(&creq->req, ctx->chacha);
skcipher_request_set_crypt(&creq->req, src, dst,
@@ -188,7 +194,7 @@ static int poly_tail(struct aead_request *req)
memcpy(&preq->tail.cryptlen, &len, sizeof(len));
sg_set_buf(preq->src, &preq->tail, sizeof(preq->tail));
- ahash_request_set_callback(&preq->req, aead_request_flags(req),
+ ahash_request_set_callback(&preq->req, rctx->flags,
poly_tail_done, req);
ahash_request_set_tfm(&preq->req, ctx->poly);
ahash_request_set_crypt(&preq->req, preq->src,
@@ -219,7 +225,7 @@ static int poly_cipherpad(struct aead_request *req)
sg_init_table(preq->src, 1);
sg_set_buf(preq->src, &preq->pad, padlen);
- ahash_request_set_callback(&preq->req, aead_request_flags(req),
+ ahash_request_set_callback(&preq->req, rctx->flags,
poly_cipherpad_done, req);
ahash_request_set_tfm(&preq->req, ctx->poly);
ahash_request_set_crypt(&preq->req, preq->src, NULL, padlen);
@@ -250,7 +256,7 @@ static int poly_cipher(struct aead_request *req)
sg_init_table(rctx->src, 2);
crypt = scatterwalk_ffwd(rctx->src, crypt, req->assoclen);
- ahash_request_set_callback(&preq->req, aead_request_flags(req),
+ ahash_request_set_callback(&preq->req, rctx->flags,
poly_cipher_done, req);
ahash_request_set_tfm(&preq->req, ctx->poly);
ahash_request_set_crypt(&preq->req, crypt, NULL, rctx->cryptlen);
@@ -280,7 +286,7 @@ static int poly_adpad(struct aead_request *req)
sg_init_table(preq->src, 1);
sg_set_buf(preq->src, preq->pad, padlen);
- ahash_request_set_callback(&preq->req, aead_request_flags(req),
+ ahash_request_set_callback(&preq->req, rctx->flags,
poly_adpad_done, req);
ahash_request_set_tfm(&preq->req, ctx->poly);
ahash_request_set_crypt(&preq->req, preq->src, NULL, padlen);
@@ -304,7 +310,7 @@ static int poly_ad(struct aead_request *req)
struct poly_req *preq = &rctx->u.poly;
int err;
- ahash_request_set_callback(&preq->req, aead_request_flags(req),
+ ahash_request_set_callback(&preq->req, rctx->flags,
poly_ad_done, req);
ahash_request_set_tfm(&preq->req, ctx->poly);
ahash_request_set_crypt(&preq->req, req->src, NULL, rctx->assoclen);
@@ -331,7 +337,7 @@ static int poly_setkey(struct aead_request *req)
sg_init_table(preq->src, 1);
sg_set_buf(preq->src, rctx->key, sizeof(rctx->key));
- ahash_request_set_callback(&preq->req, aead_request_flags(req),
+ ahash_request_set_callback(&preq->req, rctx->flags,
poly_setkey_done, req);
ahash_request_set_tfm(&preq->req, ctx->poly);
ahash_request_set_crypt(&preq->req, preq->src, NULL, sizeof(rctx->key));
@@ -355,7 +361,7 @@ static int poly_init(struct aead_request *req)
struct poly_req *preq = &rctx->u.poly;
int err;
- ahash_request_set_callback(&preq->req, aead_request_flags(req),
+ ahash_request_set_callback(&preq->req, rctx->flags,
poly_init_done, req);
ahash_request_set_tfm(&preq->req, ctx->poly);
@@ -393,7 +399,7 @@ static int poly_genkey(struct aead_request *req)
chacha_iv(creq->iv, req, 0);
- skcipher_request_set_callback(&creq->req, aead_request_flags(req),
+ skcipher_request_set_callback(&creq->req, rctx->flags,
poly_genkey_done, req);
skcipher_request_set_tfm(&creq->req, ctx->chacha);
skcipher_request_set_crypt(&creq->req, creq->src, creq->src,
@@ -433,7 +439,7 @@ static int chacha_encrypt(struct aead_request *req)
dst = scatterwalk_ffwd(rctx->dst, req->dst, req->assoclen);
}
- skcipher_request_set_callback(&creq->req, aead_request_flags(req),
+ skcipher_request_set_callback(&creq->req, rctx->flags,
chacha_encrypt_done, req);
skcipher_request_set_tfm(&creq->req, ctx->chacha);
skcipher_request_set_crypt(&creq->req, src, dst,
@@ -451,6 +457,7 @@ static int chachapoly_encrypt(struct aead_request *req)
struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
rctx->cryptlen = req->cryptlen;
+ rctx->flags = aead_request_flags(req);
/* encrypt call chain:
* - chacha_encrypt/done()
@@ -472,6 +479,7 @@ static int chachapoly_decrypt(struct aead_request *req)
struct chachapoly_req_ctx *rctx = aead_request_ctx(req);
rctx->cryptlen = req->cryptlen - POLY1305_DIGEST_SIZE;
+ rctx->flags = aead_request_flags(req);
/* decrypt call chain:
* - poly_genkey/done()
diff --git a/crypto/ghash-generic.c b/crypto/ghash-generic.c
index d9f192b..591b52d 100644
--- a/crypto/ghash-generic.c
+++ b/crypto/ghash-generic.c
@@ -34,6 +34,7 @@ static int ghash_setkey(struct crypto_shash *tfm,
const u8 *key, unsigned int keylen)
{
struct ghash_ctx *ctx = crypto_shash_ctx(tfm);
+ be128 k;
if (keylen != GHASH_BLOCK_SIZE) {
crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
@@ -42,7 +43,12 @@ static int ghash_setkey(struct crypto_shash *tfm,
if (ctx->gf128)
gf128mul_free_4k(ctx->gf128);
- ctx->gf128 = gf128mul_init_4k_lle((be128 *)key);
+
+ BUILD_BUG_ON(sizeof(k) != GHASH_BLOCK_SIZE);
+ memcpy(&k, key, GHASH_BLOCK_SIZE); /* avoid violating alignment rules */
+ ctx->gf128 = gf128mul_init_4k_lle(&k);
+ memzero_explicit(&k, GHASH_BLOCK_SIZE);
+
if (!ctx->gf128)
return -ENOMEM;
diff --git a/crypto/serpent_generic.c b/crypto/serpent_generic.c
index 7c3382f..600bd28 100644
--- a/crypto/serpent_generic.c
+++ b/crypto/serpent_generic.c
@@ -229,7 +229,13 @@
x4 ^= x2; \
})
-static void __serpent_setkey_sbox(u32 r0, u32 r1, u32 r2, u32 r3, u32 r4, u32 *k)
+/*
+ * both gcc and clang have misoptimized this function in the past,
+ * producing horrible object code from spilling temporary variables
+ * on the stack. Forcing this part out of line avoids that.
+ */
+static noinline void __serpent_setkey_sbox(u32 r0, u32 r1, u32 r2,
+ u32 r3, u32 r4, u32 *k)
{
k += 100;
S3(r3, r4, r0, r1, r2); store_and_load_keys(r1, r2, r4, r3, 28, 24);
diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h
index 704bebb..298180b 100644
--- a/drivers/acpi/acpica/acevents.h
+++ b/drivers/acpi/acpica/acevents.h
@@ -69,7 +69,8 @@ acpi_status
acpi_ev_mask_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 is_masked);
acpi_status
-acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info);
+acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info,
+ u8 clear_on_enable);
acpi_status
acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_info);
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index e10fec9..4b5d3b4 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -146,6 +146,7 @@ acpi_ev_mask_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 is_masked)
* FUNCTION: acpi_ev_add_gpe_reference
*
* PARAMETERS: gpe_event_info - Add a reference to this GPE
+ * clear_on_enable - Clear GPE status before enabling it
*
* RETURN: Status
*
@@ -155,7 +156,8 @@ acpi_ev_mask_gpe(struct acpi_gpe_event_info *gpe_event_info, u8 is_masked)
******************************************************************************/
acpi_status
-acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info)
+acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info,
+ u8 clear_on_enable)
{
acpi_status status = AE_OK;
@@ -170,6 +172,10 @@ acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info)
/* Enable on first reference */
+ if (clear_on_enable) {
+ (void)acpi_hw_clear_gpe(gpe_event_info);
+ }
+
status = acpi_ev_update_gpe_enable_mask(gpe_event_info);
if (ACPI_SUCCESS(status)) {
status = acpi_ev_enable_gpe(gpe_event_info);
diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c
index b253063..8d96270 100644
--- a/drivers/acpi/acpica/evgpeblk.c
+++ b/drivers/acpi/acpica/evgpeblk.c
@@ -453,7 +453,7 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
continue;
}
- status = acpi_ev_add_gpe_reference(gpe_event_info);
+ status = acpi_ev_add_gpe_reference(gpe_event_info, FALSE);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"Could not enable GPE 0x%02X",
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index febc332..841557b 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -971,7 +971,7 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
ACPI_GPE_DISPATCH_METHOD) ||
(ACPI_GPE_DISPATCH_TYPE(handler->original_flags) ==
ACPI_GPE_DISPATCH_NOTIFY)) && handler->originally_enabled) {
- (void)acpi_ev_add_gpe_reference(gpe_event_info);
+ (void)acpi_ev_add_gpe_reference(gpe_event_info, FALSE);
if (ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) {
/* Poll edge triggered GPEs to handle existing events */
diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c
index b2d5f66..4188731 100644
--- a/drivers/acpi/acpica/evxfgpe.c
+++ b/drivers/acpi/acpica/evxfgpe.c
@@ -108,7 +108,7 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
if (gpe_event_info) {
if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
ACPI_GPE_DISPATCH_NONE) {
- status = acpi_ev_add_gpe_reference(gpe_event_info);
+ status = acpi_ev_add_gpe_reference(gpe_event_info, TRUE);
if (ACPI_SUCCESS(status) &&
ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) {
diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c
index 995c4d8..761f0c1 100644
--- a/drivers/acpi/blacklist.c
+++ b/drivers/acpi/blacklist.c
@@ -30,7 +30,9 @@
#include "internal.h"
+#ifdef CONFIG_DMI
static const struct dmi_system_id acpi_rev_dmi_table[] __initconst;
+#endif
/*
* POLICY: If *anything* doesn't work, put it on the blacklist.
@@ -74,7 +76,9 @@ int __init acpi_blacklisted(void)
}
(void)early_acpi_osi_init();
+#ifdef CONFIG_DMI
dmi_check_system(acpi_rev_dmi_table);
+#endif
return blacklisted;
}
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index bc2d639..71e777d 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -2138,8 +2138,18 @@ static struct binder_thread *binder_get_txn_from_and_acq_inner(
static void binder_free_transaction(struct binder_transaction *t)
{
- if (t->buffer)
- t->buffer->transaction = NULL;
+ struct binder_proc *target_proc = t->to_proc;
+
+ if (target_proc) {
+ binder_inner_proc_lock(target_proc);
+ if (t->buffer)
+ t->buffer->transaction = NULL;
+ binder_inner_proc_unlock(target_proc);
+ }
+ /*
+ * If the transaction has no target_proc, then
+ * t->buffer->transaction has already been cleared.
+ */
kfree(t);
binder_stats_deleted(BINDER_STAT_TRANSACTION);
}
@@ -3104,7 +3114,7 @@ static void binder_transaction(struct binder_proc *proc,
else
return_error = BR_DEAD_REPLY;
mutex_unlock(&context->context_mgr_node_lock);
- if (target_node && target_proc == proc) {
+ if (target_node && target_proc->pid == proc->pid) {
binder_user_error("%d:%d got transaction to context manager from process owning it\n",
proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
@@ -3334,7 +3344,8 @@ static void binder_transaction(struct binder_proc *proc,
buffer_offset = off_start_offset;
off_end_offset = off_start_offset + tr->offsets_size;
sg_buf_offset = ALIGN(off_end_offset, sizeof(void *));
- sg_buf_end_offset = sg_buf_offset + extra_buffers_size;
+ sg_buf_end_offset = sg_buf_offset + extra_buffers_size -
+ ALIGN(secctx_sz, sizeof(u64));
off_min = 0;
for (buffer_offset = off_start_offset; buffer_offset < off_end_offset;
buffer_offset += sizeof(binder_size_t)) {
@@ -3847,10 +3858,12 @@ static int binder_thread_write(struct binder_proc *proc,
buffer->debug_id,
buffer->transaction ? "active" : "finished");
+ binder_inner_proc_lock(proc);
if (buffer->transaction) {
buffer->transaction->buffer = NULL;
buffer->transaction = NULL;
}
+ binder_inner_proc_unlock(proc);
if (buffer->async_transaction && buffer->target_node) {
struct binder_node *buf_node;
struct binder_work *w;
@@ -4301,6 +4314,8 @@ static int binder_thread_read(struct binder_proc *proc,
case BINDER_WORK_TRANSACTION_COMPLETE: {
binder_inner_proc_unlock(proc);
cmd = BR_TRANSACTION_COMPLETE;
+ kfree(w);
+ binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
@@ -4309,8 +4324,6 @@ static int binder_thread_read(struct binder_proc *proc,
binder_debug(BINDER_DEBUG_TRANSACTION_COMPLETE,
"%d:%d BR_TRANSACTION_COMPLETE\n",
proc->pid, thread->pid);
- kfree(w);
- binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
} break;
case BINDER_WORK_NODE: {
struct binder_node *node = container_of(w, struct binder_node, work);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 01306c0..ccc80ff 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1490,7 +1490,7 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
tf->hob_lbah = buf[10];
tf->nsect = buf[12];
tf->hob_nsect = buf[13];
- if (ata_id_has_ncq_autosense(dev->id))
+ if (dev->class == ATA_DEV_ZAC && ata_id_has_ncq_autosense(dev->id))
tf->auxiliary = buf[14] << 16 | buf[15] << 8 | buf[16];
return 0;
@@ -1737,7 +1737,8 @@ void ata_eh_analyze_ncq_error(struct ata_link *link)
memcpy(&qc->result_tf, &tf, sizeof(tf));
qc->result_tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ;
- if ((qc->result_tf.command & ATA_SENSE) || qc->result_tf.auxiliary) {
+ if (dev->class == ATA_DEV_ZAC &&
+ ((qc->result_tf.command & ATA_SENSE) || qc->result_tf.auxiliary)) {
char sense_key, asc, ascq;
sense_key = (qc->result_tf.auxiliary >> 16) & 0xff;
@@ -1791,10 +1792,11 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
}
switch (qc->dev->class) {
- case ATA_DEV_ATA:
case ATA_DEV_ZAC:
if (stat & ATA_SENSE)
ata_eh_request_sense(qc, qc->scsicmd);
+ /* fall through */
+ case ATA_DEV_ATA:
if (err & ATA_ICRC)
qc->err_mask |= AC_ERR_ATA_BUS;
if (err & (ATA_UNC | ATA_AMNF))
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
index 82532c2..008905d 100644
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -63,6 +63,7 @@
#include <asm/byteorder.h>
#include <linux/vmalloc.h>
#include <linux/jiffies.h>
+#include <linux/nospec.h>
#include "iphase.h"
#include "suni.h"
#define swap_byte_order(x) (((x & 0xff) << 8) | ((x & 0xff00) >> 8))
@@ -2760,8 +2761,11 @@ static int ia_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg)
}
if (copy_from_user(&ia_cmds, arg, sizeof ia_cmds)) return -EFAULT;
board = ia_cmds.status;
- if ((board < 0) || (board > iadev_count))
- board = 0;
+
+ if ((board < 0) || (board > iadev_count))
+ board = 0;
+ board = array_index_nospec(board, iadev_count + 1);
+
iadev = ia_dev[board];
switch (ia_cmds.cmd) {
case MEMDUMP:
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 7a419a7..559b047 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -66,6 +66,9 @@ struct driver_private {
* probed first.
* @device - pointer back to the struct device that this structure is
* associated with.
+ * @dead - This device is currently either in the process of or has been
+ * removed from the system. Any asynchronous events scheduled for this
+ * device should exit without taking any action.
*
* Nothing outside of the driver core should ever touch these fields.
*/
@@ -76,6 +79,7 @@ struct device_private {
struct klist_node knode_bus;
struct list_head deferred_probe;
struct device *device;
+ u8 dead:1;
};
#define to_device_private_parent(obj) \
container_of(obj, struct device_private, knode_parent)
diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c
index dd6a685..ce015ce2 100644
--- a/drivers/base/cacheinfo.c
+++ b/drivers/base/cacheinfo.c
@@ -653,7 +653,8 @@ static int cacheinfo_cpu_pre_down(unsigned int cpu)
static int __init cacheinfo_sysfs_init(void)
{
- return cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "base/cacheinfo:online",
+ return cpuhp_setup_state(CPUHP_AP_BASE_CACHEINFO_ONLINE,
+ "base/cacheinfo:online",
cacheinfo_cpu_online, cacheinfo_cpu_pre_down);
}
device_initcall(cacheinfo_sysfs_init);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index a7790fd..cd13be9 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -2036,6 +2036,24 @@ void put_device(struct device *dev)
}
EXPORT_SYMBOL_GPL(put_device);
+bool kill_device(struct device *dev)
+{
+ /*
+ * Require the device lock and set the "dead" flag to guarantee that
+ * the update behavior is consistent with the other bitfields near
+ * it and that we cannot have an asynchronous probe routine trying
+ * to run while we are tearing out the bus/class/sysfs from
+ * underneath the device.
+ */
+ lockdep_assert_held(&dev->mutex);
+
+ if (dev->p->dead)
+ return false;
+ dev->p->dead = true;
+ return true;
+}
+EXPORT_SYMBOL_GPL(kill_device);
+
/**
* device_del - delete device from system.
* @dev: device.
@@ -2055,6 +2073,10 @@ void device_del(struct device *dev)
struct kobject *glue_dir = NULL;
struct class_interface *class_intf;
+ device_lock(dev);
+ kill_device(dev);
+ device_unlock(dev);
+
/* Notify clients of device removal. This call must come
* before dpm_sysfs_remove().
*/
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 7d53342..b7e156f 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -746,15 +746,6 @@ static int __device_attach_driver(struct device_driver *drv, void *_data)
bool async_allowed;
int ret;
- /*
- * Check if device has already been claimed. This may
- * happen with driver loading, device discovery/registration,
- * and deferred probe processing happens all at once with
- * multiple threads.
- */
- if (dev->driver)
- return -EBUSY;
-
ret = driver_match_device(drv, dev);
if (ret == 0) {
/* no match */
@@ -789,6 +780,15 @@ static void __device_attach_async_helper(void *_dev, async_cookie_t cookie)
device_lock(dev);
+ /*
+ * Check if device has already been removed or claimed. This may
+ * happen with driver loading, device discovery/registration,
+ * and deferred probe processing happens all at once with
+ * multiple threads.
+ */
+ if (dev->p->dead || dev->driver)
+ goto out_unlock;
+
if (dev->parent)
pm_runtime_get_sync(dev->parent);
@@ -799,7 +799,7 @@ static void __device_attach_async_helper(void *_dev, async_cookie_t cookie)
if (dev->parent)
pm_runtime_put(dev->parent);
-
+out_unlock:
device_unlock(dev);
put_device(dev);
@@ -912,7 +912,7 @@ static int __driver_attach(struct device *dev, void *data)
if (dev->parent && dev->bus->need_parent_lock)
device_lock(dev->parent);
device_lock(dev);
- if (!dev->driver)
+ if (!dev->p->dead && !dev->driver)
driver_probe_device(drv, dev);
device_unlock(dev);
if (dev->parent && dev->bus->need_parent_lock)
diff --git a/drivers/base/firmware_loader/fallback.c b/drivers/base/firmware_loader/fallback.c
index b5c865f..818d8c3 100644
--- a/drivers/base/firmware_loader/fallback.c
+++ b/drivers/base/firmware_loader/fallback.c
@@ -659,7 +659,7 @@ static bool fw_run_sysfs_fallback(enum fw_opt opt_flags)
/* Also permit LSMs and IMA to fail firmware sysfs fallback */
ret = security_kernel_load_data(LOADING_FIRMWARE);
if (ret < 0)
- return ret;
+ return false;
return fw_force_sysfs_fallback(opt_flags);
}
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index 6bb38c1..5856f45 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -635,6 +635,8 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
}
if (!strcmp(name, "dummy")) {
+ kfree(map->debugfs_name);
+
map->debugfs_name = kasprintf(GFP_KERNEL, "dummy%d",
dummy_index);
name = map->debugfs_name;
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index 429ca8e..982c7ac 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -91,6 +91,9 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
* suppress pointless writes.
*/
for (i = 0; i < d->chip->num_regs; i++) {
+ if (!d->chip->mask_base)
+ continue;
+
reg = d->chip->mask_base +
(i * map->reg_stride * d->irq_reg_stride);
if (d->chip->mask_invert) {
@@ -526,6 +529,9 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
/* Mask all the interrupts by default */
for (i = 0; i < chip->num_regs; i++) {
d->mask_buf[i] = d->mask_buf_def[i];
+ if (!chip->mask_base)
+ continue;
+
reg = chip->mask_base +
(i * map->reg_stride * d->irq_reg_stride);
if (chip->mask_invert)
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 0360a90..6c9f698 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -1618,6 +1618,8 @@ static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg,
map->format.reg_bytes +
map->format.pad_bytes,
val, val_len);
+ else
+ ret = -ENOTSUPP;
/* If that didn't work fall back on linearising by hand. */
if (ret == -ENOTSUPP) {
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index a8de56f..4a9a4d1 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -2119,6 +2119,9 @@ static void setup_format_params(int track)
raw_cmd->kernel_data = floppy_track_buffer;
raw_cmd->length = 4 * F_SECT_PER_TRACK;
+ if (!F_SECT_PER_TRACK)
+ return;
+
/* allow for about 30ms for data transport per track */
head_shift = (F_SECT_PER_TRACK + 5) / 6;
@@ -3241,8 +3244,12 @@ static int set_geometry(unsigned int cmd, struct floppy_struct *g,
int cnt;
/* sanity checking for parameters. */
- if (g->sect <= 0 ||
- g->head <= 0 ||
+ if ((int)g->sect <= 0 ||
+ (int)g->head <= 0 ||
+ /* check for overflow in max_sector */
+ (int)(g->sect * g->head) <= 0 ||
+ /* check for zero in F_SECT_PER_TRACK */
+ (unsigned char)((g->sect << 2) >> FD_SIZECODE(g)) == 0 ||
g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
/* check if reserved bits are set */
(g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
@@ -3386,6 +3393,24 @@ static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return 0;
}
+static bool valid_floppy_drive_params(const short autodetect[8],
+ int native_format)
+{
+ size_t floppy_type_size = ARRAY_SIZE(floppy_type);
+ size_t i = 0;
+
+ for (i = 0; i < 8; ++i) {
+ if (autodetect[i] < 0 ||
+ autodetect[i] >= floppy_type_size)
+ return false;
+ }
+
+ if (native_format < 0 || native_format >= floppy_type_size)
+ return false;
+
+ return true;
+}
+
static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
unsigned long param)
{
@@ -3512,6 +3537,9 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
SUPBOUND(size, strlen((const char *)outparam) + 1);
break;
case FDSETDRVPRM:
+ if (!valid_floppy_drive_params(inparam.dp.autodetect,
+ inparam.dp.native_format))
+ return -EINVAL;
*UDP = inparam.dp;
break;
case FDGETDRVPRM:
@@ -3709,6 +3737,8 @@ static int compat_setdrvprm(int drive,
return -EPERM;
if (copy_from_user(&v, arg, sizeof(struct compat_floppy_drive_params)))
return -EFAULT;
+ if (!valid_floppy_drive_params(v.autodetect, v.native_format))
+ return -EINVAL;
mutex_lock(&floppy_mutex);
UDP->cmos = v.cmos;
UDP->max_dtr = v.max_dtr;
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index c13a6d1..fa60f26 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -1218,7 +1218,7 @@ static void nbd_clear_sock_ioctl(struct nbd_device *nbd,
struct block_device *bdev)
{
sock_shutdown(nbd);
- kill_bdev(bdev);
+ __invalidate_device(bdev, true);
nbd_bdev_reset(bdev);
if (test_and_clear_bit(NBD_HAS_CONFIG_REF,
&nbd->config->runtime_flags))
diff --git a/drivers/block/null_blk_main.c b/drivers/block/null_blk_main.c
index 093b614..c5c0b7c 100644
--- a/drivers/block/null_blk_main.c
+++ b/drivers/block/null_blk_main.c
@@ -321,11 +321,12 @@ static ssize_t nullb_device_power_store(struct config_item *item,
set_bit(NULLB_DEV_FL_CONFIGURED, &dev->flags);
dev->power = newp;
} else if (dev->power && !newp) {
- mutex_lock(&lock);
- dev->power = newp;
- null_del_dev(dev->nullb);
- mutex_unlock(&lock);
- clear_bit(NULLB_DEV_FL_UP, &dev->flags);
+ if (test_and_clear_bit(NULLB_DEV_FL_UP, &dev->flags)) {
+ mutex_lock(&lock);
+ dev->power = newp;
+ null_del_dev(dev->nullb);
+ mutex_unlock(&lock);
+ }
clear_bit(NULLB_DEV_FL_CONFIGURED, &dev->flags);
}
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 40a4f95..75cf605 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -277,7 +277,9 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x04ca, 0x3015), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x04ca, 0x3016), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x04ca, 0x301a), .driver_info = BTUSB_QCA_ROME },
+ { USB_DEVICE(0x13d3, 0x3491), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x13d3, 0x3496), .driver_info = BTUSB_QCA_ROME },
+ { USB_DEVICE(0x13d3, 0x3501), .driver_info = BTUSB_QCA_ROME },
/* Broadcom BCM2035 */
{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 },
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
index d568fbd..2023592 100644
--- a/drivers/bluetooth/hci_ath.c
+++ b/drivers/bluetooth/hci_ath.c
@@ -112,6 +112,9 @@ static int ath_open(struct hci_uart *hu)
BT_DBG("hu %p", hu);
+ if (!hci_uart_has_flow_control(hu))
+ return -EOPNOTSUPP;
+
ath = kzalloc(sizeof(*ath), GFP_KERNEL);
if (!ath)
return -ENOMEM;
diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c
index 8001323..aa6b7ed 100644
--- a/drivers/bluetooth/hci_bcm.c
+++ b/drivers/bluetooth/hci_bcm.c
@@ -369,6 +369,9 @@ static int bcm_open(struct hci_uart *hu)
bt_dev_dbg(hu->hdev, "hu %p", hu);
+ if (!hci_uart_has_flow_control(hu))
+ return -EOPNOTSUPP;
+
bcm = kzalloc(sizeof(*bcm), GFP_KERNEL);
if (!bcm)
return -ENOMEM;
diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c
index 1a7f0c8..66fe1e6 100644
--- a/drivers/bluetooth/hci_bcsp.c
+++ b/drivers/bluetooth/hci_bcsp.c
@@ -759,6 +759,11 @@ static int bcsp_close(struct hci_uart *hu)
skb_queue_purge(&bcsp->rel);
skb_queue_purge(&bcsp->unrel);
+ if (bcsp->rx_skb) {
+ kfree_skb(bcsp->rx_skb);
+ bcsp->rx_skb = NULL;
+ }
+
kfree(bcsp);
return 0;
}
diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c
index 46ace32..e922852 100644
--- a/drivers/bluetooth/hci_intel.c
+++ b/drivers/bluetooth/hci_intel.c
@@ -406,6 +406,9 @@ static int intel_open(struct hci_uart *hu)
BT_DBG("hu %p", hu);
+ if (!hci_uart_has_flow_control(hu))
+ return -EOPNOTSUPP;
+
intel = kzalloc(sizeof(*intel), GFP_KERNEL);
if (!intel)
return -ENOMEM;
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index c915daf0..efeb813 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -299,6 +299,19 @@ static int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
return 0;
}
+/* Check the underlying device or tty has flow control support */
+bool hci_uart_has_flow_control(struct hci_uart *hu)
+{
+ /* serdev nodes check if the needed operations are present */
+ if (hu->serdev)
+ return true;
+
+ if (hu->tty->driver->ops->tiocmget && hu->tty->driver->ops->tiocmset)
+ return true;
+
+ return false;
+}
+
/* Flow control or un-flow control the device */
void hci_uart_set_flow_control(struct hci_uart *hu, bool enable)
{
diff --git a/drivers/bluetooth/hci_mrvl.c b/drivers/bluetooth/hci_mrvl.c
index ffb0066..23791df 100644
--- a/drivers/bluetooth/hci_mrvl.c
+++ b/drivers/bluetooth/hci_mrvl.c
@@ -66,6 +66,9 @@ static int mrvl_open(struct hci_uart *hu)
BT_DBG("hu %p", hu);
+ if (!hci_uart_has_flow_control(hu))
+ return -EOPNOTSUPP;
+
mrvl = kzalloc(sizeof(*mrvl), GFP_KERNEL);
if (!mrvl)
return -ENOMEM;
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index 77004c2..f96e58d 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -450,6 +450,9 @@ static int qca_open(struct hci_uart *hu)
BT_DBG("hu %p qca_open", hu);
+ if (!hci_uart_has_flow_control(hu))
+ return -EOPNOTSUPP;
+
qca = kzalloc(sizeof(struct qca_data), GFP_KERNEL);
if (!qca)
return -ENOMEM;
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
index 00cab2f..067a610 100644
--- a/drivers/bluetooth/hci_uart.h
+++ b/drivers/bluetooth/hci_uart.h
@@ -118,6 +118,7 @@ int hci_uart_tx_wakeup(struct hci_uart *hu);
int hci_uart_init_ready(struct hci_uart *hu);
void hci_uart_init_work(struct work_struct *work);
void hci_uart_set_baudrate(struct hci_uart *hu, unsigned int speed);
+bool hci_uart_has_flow_control(struct hci_uart *hu);
void hci_uart_set_flow_control(struct hci_uart *hu, bool enable);
void hci_uart_set_speeds(struct hci_uart *hu, unsigned int init_speed,
unsigned int oper_speed);
diff --git a/drivers/bus/mhi/controllers/mhi_arch_qcom.c b/drivers/bus/mhi/controllers/mhi_arch_qcom.c
index cdb334b..a19b806 100644
--- a/drivers/bus/mhi/controllers/mhi_arch_qcom.c
+++ b/drivers/bus/mhi/controllers/mhi_arch_qcom.c
@@ -31,8 +31,6 @@ struct arch_info {
void *boot_ipc_log;
void *tsync_ipc_log;
struct mhi_device *boot_dev;
- struct mhi_link_info current_link_info;
- struct work_struct bw_scale_work;
bool drv_connected;
struct notifier_block pm_notifier;
struct completion pm_completion;
@@ -346,7 +344,7 @@ static int mhi_arch_pcie_scale_bw(struct mhi_controller *mhi_cntrl,
struct pci_dev *pci_dev,
struct mhi_link_info *link_info)
{
- int ret, scale;
+ int ret;
mhi_cntrl->lpm_disable(mhi_cntrl, mhi_cntrl->priv_data);
ret = msm_pcie_set_link_bandwidth(pci_dev, link_info->target_link_speed,
@@ -356,60 +354,22 @@ static int mhi_arch_pcie_scale_bw(struct mhi_controller *mhi_cntrl,
if (ret)
return ret;
- /* if we switch to low bw release bus scale voting */
- scale = !(link_info->target_link_speed == PCI_EXP_LNKSTA_CLS_2_5GB);
- mhi_arch_set_bus_request(mhi_cntrl, scale);
+ /* do a bus scale vote based on gen speeds */
+ mhi_arch_set_bus_request(mhi_cntrl, link_info->target_link_speed);
- MHI_VERB("bw changed to speed:0x%x width:0x%x bus_scale:%d\n",
- link_info->target_link_speed, link_info->target_link_width,
- scale);
+ MHI_VERB("bw changed to speed:0x%x width:0x%x\n",
+ link_info->target_link_speed, link_info->target_link_width);
return 0;
}
-static void mhi_arch_pcie_bw_scale_work(struct work_struct *work)
+static int mhi_arch_bw_scale(struct mhi_controller *mhi_cntrl,
+ struct mhi_link_info *link_info)
{
- struct arch_info *arch_info = container_of(work,
- struct arch_info,
- bw_scale_work);
- struct mhi_dev *mhi_dev = arch_info->mhi_dev;
+ struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl);
struct pci_dev *pci_dev = mhi_dev->pci_dev;
- struct device *dev = &pci_dev->dev;
- struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev);
- struct mhi_link_info mhi_link_info;
- struct mhi_link_info *cur_info = &arch_info->current_link_info;
- int ret;
- mutex_lock(&mhi_cntrl->pm_mutex);
- if (!mhi_dev->powered_on || MHI_IS_SUSPENDED(mhi_dev->suspend_mode))
- goto exit_work;
-
- /* copy the latest speed change */
- write_lock_irq(&mhi_cntrl->pm_lock);
- mhi_link_info = mhi_cntrl->mhi_link_info;
- write_unlock_irq(&mhi_cntrl->pm_lock);
-
- /* link is already set to current settings */
- if (cur_info->target_link_speed == mhi_link_info.target_link_speed &&
- cur_info->target_link_width == mhi_link_info.target_link_width)
- goto exit_work;
-
- ret = mhi_arch_pcie_scale_bw(mhi_cntrl, pci_dev, &mhi_link_info);
- if (ret)
- goto exit_work;
-
- *cur_info = mhi_link_info;
-
-exit_work:
- mutex_unlock(&mhi_cntrl->pm_mutex);
-}
-
-static void mhi_arch_pcie_bw_scale_cb(struct mhi_controller *mhi_cntrl,
- struct mhi_dev *mhi_dev)
-{
- struct arch_info *arch_info = mhi_dev->arch_info;
-
- schedule_work(&arch_info->bw_scale_work);
+ return mhi_arch_pcie_scale_bw(mhi_cntrl, pci_dev, link_info);
}
static int mhi_bl_probe(struct mhi_device *mhi_device,
@@ -454,6 +414,7 @@ int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl)
{
struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl);
struct arch_info *arch_info = mhi_dev->arch_info;
+ struct mhi_link_info *cur_link_info;
char node[32];
int ret;
u16 linkstat;
@@ -462,7 +423,6 @@ int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl)
struct msm_pcie_register_event *reg_event;
struct pci_dev *root_port;
struct device_node *root_ofnode;
- struct mhi_link_info *cur_link_info;
arch_info = devm_kzalloc(&mhi_dev->pci_dev->dev,
sizeof(*arch_info), GFP_KERNEL);
@@ -566,28 +526,24 @@ int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl)
mhi_dev->pci_dev, NULL, 0);
mhi_dev->pci_dev->no_d3hot = true;
- INIT_WORK(&arch_info->bw_scale_work,
- mhi_arch_pcie_bw_scale_work);
- mhi_dev->bw_scale = mhi_arch_pcie_bw_scale_cb;
-
- /* store the current bw info */
- ret = pcie_capability_read_word(mhi_dev->pci_dev,
- PCI_EXP_LNKSTA, &linkstat);
- if (ret)
- return ret;
-
- cur_link_info = &arch_info->current_link_info;
- cur_link_info->target_link_speed =
- linkstat & PCI_EXP_LNKSTA_CLS;
- cur_link_info->target_link_width =
- (linkstat & PCI_EXP_LNKSTA_NLW) >>
- PCI_EXP_LNKSTA_NLW_SHIFT;
- mhi_cntrl->mhi_link_info = *cur_link_info;
+ mhi_cntrl->bw_scale = mhi_arch_bw_scale;
mhi_driver_register(&mhi_bl_driver);
}
- return mhi_arch_set_bus_request(mhi_cntrl, 1);
+ /* store the current bw info */
+ ret = pcie_capability_read_word(mhi_dev->pci_dev,
+ PCI_EXP_LNKSTA, &linkstat);
+ if (ret)
+ return ret;
+
+ cur_link_info = &mhi_cntrl->mhi_link_info;
+ cur_link_info->target_link_speed = linkstat & PCI_EXP_LNKSTA_CLS;
+ cur_link_info->target_link_width = (linkstat & PCI_EXP_LNKSTA_NLW) >>
+ PCI_EXP_LNKSTA_NLW_SHIFT;
+
+ return mhi_arch_set_bus_request(mhi_cntrl,
+ cur_link_info->target_link_speed);
}
void mhi_arch_pcie_deinit(struct mhi_controller *mhi_cntrl)
@@ -598,13 +554,12 @@ void mhi_arch_pcie_deinit(struct mhi_controller *mhi_cntrl)
static int mhi_arch_drv_suspend(struct mhi_controller *mhi_cntrl)
{
struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl);
- struct arch_info *arch_info = mhi_dev->arch_info;
struct pci_dev *pci_dev = mhi_dev->pci_dev;
struct mhi_link_info link_info, *cur_link_info;
bool bw_switched = false;
int ret;
- cur_link_info = &arch_info->current_link_info;
+ cur_link_info = &mhi_cntrl->mhi_link_info;
/* if link is not in gen 1 we need to switch to gen 1 */
if (cur_link_info->target_link_speed != PCI_EXP_LNKSTA_CLS_2_5GB) {
link_info.target_link_speed = PCI_EXP_LNKSTA_CLS_2_5GB;
@@ -630,9 +585,6 @@ static int mhi_arch_drv_suspend(struct mhi_controller *mhi_cntrl)
return ret;
}
- if (bw_switched)
- *cur_link_info = link_info;
-
return ret;
}
@@ -689,17 +641,16 @@ static int __mhi_arch_link_resume(struct mhi_controller *mhi_cntrl)
struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl);
struct arch_info *arch_info = mhi_dev->arch_info;
struct pci_dev *pci_dev = mhi_dev->pci_dev;
- struct mhi_link_info *cur_info = &arch_info->current_link_info;
+ struct mhi_link_info *cur_info = &mhi_cntrl->mhi_link_info;
int ret;
MHI_LOG("Entered\n");
- /* request bus scale voting if we're on Gen 2 or higher speed */
- if (cur_info->target_link_speed != PCI_EXP_LNKSTA_CLS_2_5GB) {
- ret = mhi_arch_set_bus_request(mhi_cntrl, 1);
- if (ret)
- MHI_LOG("Could not set bus frequency, ret:%d\n", ret);
- }
+ /* request bus scale voting based on higher gen speed */
+ ret = mhi_arch_set_bus_request(mhi_cntrl,
+ cur_info->target_link_speed);
+ if (ret)
+ MHI_LOG("Could not set bus frequency, ret:%d\n", ret);
ret = msm_pcie_pm_control(MSM_PCIE_RESUME, mhi_cntrl->bus, pci_dev,
NULL, 0);
@@ -733,10 +684,8 @@ static int __mhi_arch_link_resume(struct mhi_controller *mhi_cntrl)
int mhi_arch_link_resume(struct mhi_controller *mhi_cntrl)
{
struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl);
- struct arch_info *arch_info = mhi_dev->arch_info;
struct pci_dev *pci_dev = mhi_dev->pci_dev;
- struct mhi_link_info *cur_info = &arch_info->current_link_info;
- struct mhi_link_info *updated_info = &mhi_cntrl->mhi_link_info;
+ struct mhi_link_info *cur_info = &mhi_cntrl->mhi_link_info;
int ret = 0;
MHI_LOG("Entered\n");
@@ -748,6 +697,19 @@ int mhi_arch_link_resume(struct mhi_controller *mhi_cntrl)
case MHI_FAST_LINK_OFF:
ret = msm_pcie_pm_control(MSM_PCIE_RESUME, mhi_cntrl->bus,
pci_dev, NULL, 0);
+ if (ret ||
+ cur_info->target_link_speed == PCI_EXP_LNKSTA_CLS_2_5GB)
+ break;
+
+ /*
+ * BW request from device isn't for gen 1 link speed, we can
+ * only print an error here.
+ */
+ if (mhi_arch_pcie_scale_bw(mhi_cntrl, pci_dev, cur_info))
+ MHI_ERR(
+ "Failed to honor bw request: speed:0x%x width:0x%x\n",
+ cur_info->target_link_speed,
+ cur_info->target_link_width);
break;
case MHI_ACTIVE_STATE:
case MHI_FAST_LINK_ON:
@@ -759,14 +721,6 @@ int mhi_arch_link_resume(struct mhi_controller *mhi_cntrl)
return ret;
}
- /* BW request from device doesn't match current link speed */
- if (cur_info->target_link_speed != updated_info->target_link_speed ||
- cur_info->target_link_width != updated_info->target_link_width) {
- ret = mhi_arch_pcie_scale_bw(mhi_cntrl, pci_dev, updated_info);
- if (!ret)
- *cur_info = *updated_info;
- }
-
msm_pcie_l1ss_timeout_enable(pci_dev);
MHI_LOG("Exited\n");
diff --git a/drivers/bus/mhi/controllers/mhi_qcom.c b/drivers/bus/mhi/controllers/mhi_qcom.c
index c7002ec..67e12b5 100644
--- a/drivers/bus/mhi/controllers/mhi_qcom.c
+++ b/drivers/bus/mhi/controllers/mhi_qcom.c
@@ -609,10 +609,6 @@ static void mhi_status_cb(struct mhi_controller *mhi_cntrl,
pm_runtime_mark_last_busy(dev);
pm_request_autosuspend(dev);
break;
- case MHI_CB_BW_REQ:
- if (mhi_dev->bw_scale)
- mhi_dev->bw_scale(mhi_cntrl, mhi_dev);
- break;
case MHI_CB_EE_MISSION_MODE:
/*
* we need to force a suspend so device can switch to
diff --git a/drivers/bus/mhi/controllers/mhi_qcom.h b/drivers/bus/mhi/controllers/mhi_qcom.h
index fdab799..6fbbac9 100644
--- a/drivers/bus/mhi/controllers/mhi_qcom.h
+++ b/drivers/bus/mhi/controllers/mhi_qcom.h
@@ -48,9 +48,6 @@ struct mhi_dev {
dma_addr_t iova_stop;
enum mhi_suspend_mode suspend_mode;
- /* if set, soc support dynamic bw scaling */
- void (*bw_scale)(struct mhi_controller *mhi_cntrl,
- struct mhi_dev *mhi_dev);
unsigned int lpm_disable_depth;
/* lock to toggle low power modes */
spinlock_t lpm_lock;
diff --git a/drivers/bus/mhi/core/mhi_dtr.c b/drivers/bus/mhi/core/mhi_dtr.c
index 73cf01e..db33e95 100644
--- a/drivers/bus/mhi/core/mhi_dtr.c
+++ b/drivers/bus/mhi/core/mhi_dtr.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2018, The Linux Foundation. All rights reserved.*/
+/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.*/
#include <linux/debugfs.h>
#include <linux/device.h>
@@ -164,6 +164,9 @@ static void mhi_dtr_dl_xfer_cb(struct mhi_device *mhi_dev,
if (dtr_msg->msg & CTRL_MSG_RI)
mhi_dev->tiocm |= TIOCM_RI;
spin_unlock_irq(res_lock);
+
+ /* Notify the update */
+ mhi_notify(mhi_dev, MHI_CB_DTR_SIGNAL);
}
static void mhi_dtr_ul_xfer_cb(struct mhi_device *mhi_dev,
diff --git a/drivers/bus/mhi/core/mhi_init.c b/drivers/bus/mhi/core/mhi_init.c
index c76d3a4..6f88d91 100644
--- a/drivers/bus/mhi/core/mhi_init.c
+++ b/drivers/bus/mhi/core/mhi_init.c
@@ -183,7 +183,7 @@ void mhi_deinit_free_irq(struct mhi_controller *mhi_cntrl)
struct mhi_event *mhi_event = mhi_cntrl->mhi_event;
for (i = 0; i < mhi_cntrl->total_ev_rings; i++, mhi_event++) {
- if (mhi_event->offload_ev)
+ if (!mhi_event->request_irq)
continue;
free_irq(mhi_cntrl->irq[mhi_event->msi], mhi_event);
@@ -207,7 +207,7 @@ int mhi_init_irq_setup(struct mhi_controller *mhi_cntrl)
return ret;
for (i = 0; i < mhi_cntrl->total_ev_rings; i++, mhi_event++) {
- if (mhi_event->offload_ev)
+ if (!mhi_event->request_irq)
continue;
ret = request_irq(mhi_cntrl->irq[mhi_event->msi],
@@ -224,7 +224,7 @@ int mhi_init_irq_setup(struct mhi_controller *mhi_cntrl)
error_request:
for (--i, --mhi_event; i >= 0; i--, mhi_event--) {
- if (mhi_event->offload_ev)
+ if (!mhi_event->request_irq)
continue;
free_irq(mhi_cntrl->irq[mhi_event->msi], mhi_event);
@@ -496,15 +496,18 @@ int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl)
return ret;
}
-static int mhi_get_tsync_er_cfg(struct mhi_controller *mhi_cntrl)
+/* to be used only if a single event ring with the type is present */
+static int mhi_get_er_index(struct mhi_controller *mhi_cntrl,
+ enum mhi_er_data_type type)
{
int i;
struct mhi_event *mhi_event = mhi_cntrl->mhi_event;
- /* find event ring with timesync support */
- for (i = 0; i < mhi_cntrl->total_ev_rings; i++, mhi_event++)
- if (mhi_event->data_type == MHI_ER_TSYNC_ELEMENT_TYPE)
+ /* find event ring for requested type */
+ for (i = 0; i < mhi_cntrl->total_ev_rings; i++, mhi_event++) {
+ if (mhi_event->data_type == type)
return mhi_event->er_index;
+ }
return -ENOENT;
}
@@ -581,7 +584,7 @@ int mhi_init_timesync(struct mhi_controller *mhi_cntrl)
read_unlock_bh(&mhi_cntrl->pm_lock);
/* get time-sync event ring configuration */
- ret = mhi_get_tsync_er_cfg(mhi_cntrl);
+ ret = mhi_get_er_index(mhi_cntrl, MHI_ER_TSYNC_ELEMENT_TYPE);
if (ret < 0) {
MHI_LOG("Could not find timesync event ring\n");
return ret;
@@ -611,6 +614,36 @@ int mhi_init_timesync(struct mhi_controller *mhi_cntrl)
return ret;
}
+static int mhi_init_bw_scale(struct mhi_controller *mhi_cntrl)
+{
+ int ret, er_index;
+ u32 bw_cfg_offset;
+
+ /* controller doesn't support dynamic bw switch */
+ if (!mhi_cntrl->bw_scale)
+ return -ENODEV;
+
+ ret = mhi_get_capability_offset(mhi_cntrl, BW_SCALE_CAP_ID,
+ &bw_cfg_offset);
+ if (ret)
+ return ret;
+
+ /* No ER configured to support BW scale */
+ er_index = mhi_get_er_index(mhi_cntrl, MHI_ER_BW_SCALE_ELEMENT_TYPE);
+ if (ret < 0)
+ return er_index;
+
+ bw_cfg_offset += BW_SCALE_CFG_OFFSET;
+
+ MHI_LOG("BW_CFG OFFSET:0x%x\n", bw_cfg_offset);
+
+ /* advertise host support */
+ mhi_write_reg(mhi_cntrl, mhi_cntrl->regs, bw_cfg_offset,
+ MHI_BW_SCALE_SETUP(er_index));
+
+ return 0;
+}
+
int mhi_init_mmio(struct mhi_controller *mhi_cntrl)
{
u32 val;
@@ -707,6 +740,9 @@ int mhi_init_mmio(struct mhi_controller *mhi_cntrl)
mhi_write_reg(mhi_cntrl, mhi_cntrl->wake_db, 0, 0);
mhi_cntrl->wake_set = false;
+ /* setup bw scale db */
+ mhi_cntrl->bw_scale_db = base + val + (8 * MHI_BW_SCALE_CHAN_DB);
+
/* setup channel db addresses */
mhi_chan = mhi_cntrl->mhi_chan;
for (i = 0; i < mhi_cntrl->max_chan; i++, val += 8, mhi_chan++)
@@ -737,6 +773,9 @@ int mhi_init_mmio(struct mhi_controller *mhi_cntrl)
reg_info[i].mask, reg_info[i].shift,
reg_info[i].val);
+ /* setup bandwidth scaling features */
+ mhi_init_bw_scale(mhi_cntrl);
+
return 0;
}
@@ -887,6 +926,8 @@ static int of_parse_ev_cfg(struct mhi_controller *mhi_cntrl,
if (!mhi_cntrl->mhi_event)
return -ENOMEM;
+ INIT_LIST_HEAD(&mhi_cntrl->lp_ev_rings);
+
/* populate ev ring */
mhi_event = mhi_cntrl->mhi_event;
i = 0;
@@ -952,6 +993,9 @@ static int of_parse_ev_cfg(struct mhi_controller *mhi_cntrl,
case MHI_ER_TSYNC_ELEMENT_TYPE:
mhi_event->process_event = mhi_process_tsync_event_ring;
break;
+ case MHI_ER_BW_SCALE_ELEMENT_TYPE:
+ mhi_event->process_event = mhi_process_bw_scale_ev_ring;
+ break;
}
mhi_event->hw_ring = of_property_read_bool(child, "mhi,hw-ev");
@@ -963,6 +1007,19 @@ static int of_parse_ev_cfg(struct mhi_controller *mhi_cntrl,
"mhi,client-manage");
mhi_event->offload_ev = of_property_read_bool(child,
"mhi,offload");
+
+ /*
+ * low priority events are handled in a separate worker thread
+ * to allow for sleeping functions to be called.
+ */
+ if (!mhi_event->offload_ev) {
+ if (IS_MHI_ER_PRIORITY_LOW(mhi_event))
+ list_add_tail(&mhi_event->node,
+ &mhi_cntrl->lp_ev_rings);
+ else
+ mhi_event->request_irq = true;
+ }
+
mhi_event++;
}
@@ -1242,6 +1299,7 @@ int of_register_mhi_controller(struct mhi_controller *mhi_cntrl)
INIT_WORK(&mhi_cntrl->st_worker, mhi_pm_st_worker);
INIT_WORK(&mhi_cntrl->fw_worker, mhi_fw_load_worker);
INIT_WORK(&mhi_cntrl->syserr_worker, mhi_pm_sys_err_worker);
+ INIT_WORK(&mhi_cntrl->low_priority_worker, mhi_low_priority_worker);
init_waitqueue_head(&mhi_cntrl->state_event);
mhi_cmd = mhi_cntrl->mhi_cmd;
@@ -1255,6 +1313,10 @@ int of_register_mhi_controller(struct mhi_controller *mhi_cntrl)
mhi_event->mhi_cntrl = mhi_cntrl;
spin_lock_init(&mhi_event->lock);
+
+ if (IS_MHI_ER_PRIORITY_LOW(mhi_event))
+ continue;
+
if (mhi_event->data_type == MHI_ER_CTRL_ELEMENT_TYPE)
tasklet_init(&mhi_event->task, mhi_ctrl_ev_task,
(ulong)mhi_event);
diff --git a/drivers/bus/mhi/core/mhi_internal.h b/drivers/bus/mhi/core/mhi_internal.h
index e06e76e..84a9626 100644
--- a/drivers/bus/mhi/core/mhi_internal.h
+++ b/drivers/bus/mhi/core/mhi_internal.h
@@ -8,6 +8,7 @@ extern struct bus_type mhi_bus_type;
/* MHI mmio register mapping */
#define PCI_INVALID_READ(val) (val == U32_MAX)
+#define MHI_REG_SIZE (SZ_4K)
#define MHIREGLEN (0x0)
#define MHIREGLEN_MHIREGLEN_MASK (0xFFFFFFFF)
@@ -153,6 +154,17 @@ extern struct bus_type mhi_bus_type;
#define TIMESYNC_CAP_ID (2)
+/* MHI Bandwidth scaling offsets */
+#define BW_SCALE_CFG_OFFSET (0x04)
+#define BW_SCALE_CFG_CHAN_DB_ID_MASK (0xFE000000)
+#define BW_SCALE_CFG_CHAN_DB_ID_SHIFT (25)
+#define BW_SCALE_CFG_ENABLED_MASK (0x01000000)
+#define BW_SCALE_CFG_ENABLED_SHIFT (24)
+#define BW_SCALE_CFG_ER_ID_MASK (0x00F80000)
+#define BW_SCALE_CFG_ER_ID_SHIFT (19)
+
+#define BW_SCALE_CAP_ID (3)
+
/* MHI BHI offfsets */
#define BHI_BHIVERSION_MINOR (0x00)
#define BHI_BHIVERSION_MAJOR (0x04)
@@ -329,12 +341,13 @@ enum mhi_cmd_type {
#define MHI_TRE_GET_EV_TYPE(tre) (((tre)->dword[1] >> 16) & 0xFF)
#define MHI_TRE_GET_EV_STATE(tre) (((tre)->dword[0] >> 24) & 0xFF)
#define MHI_TRE_GET_EV_EXECENV(tre) (((tre)->dword[0] >> 24) & 0xFF)
-#define MHI_TRE_GET_EV_SEQ(tre) ((tre)->dword[0])
+#define MHI_TRE_GET_EV_TSYNC_SEQ(tre) ((tre)->dword[0])
#define MHI_TRE_GET_EV_TIME(tre) ((tre)->ptr)
#define MHI_TRE_GET_EV_COOKIE(tre) lower_32_bits((tre)->ptr)
#define MHI_TRE_GET_EV_VEID(tre) (((tre)->dword[0] >> 16) & 0xFF)
#define MHI_TRE_GET_EV_LINKSPEED(tre) (((tre)->dword[1] >> 24) & 0xFF)
#define MHI_TRE_GET_EV_LINKWIDTH(tre) ((tre)->dword[0] & 0xFF)
+#define MHI_TRE_GET_EV_BW_REQ_SEQ(tre) (((tre)->dword[0] >> 8) & 0xFF)
/* transfer descriptor macros */
#define MHI_TRE_DATA_PTR(ptr) (ptr)
@@ -492,19 +505,38 @@ enum MHI_XFER_TYPE {
#define NR_OF_CMD_RINGS (1)
#define CMD_EL_PER_RING (128)
#define PRIMARY_CMD_RING (0)
+#define MHI_BW_SCALE_CHAN_DB (126)
#define MHI_DEV_WAKE_DB (127)
#define MHI_MAX_MTU (0xffff)
+#define MHI_BW_SCALE_SETUP(er_index) ((MHI_BW_SCALE_CHAN_DB << \
+ BW_SCALE_CFG_CHAN_DB_ID_SHIFT) & BW_SCALE_CFG_CHAN_DB_ID_MASK | \
+ (1 << BW_SCALE_CFG_ENABLED_SHIFT) & BW_SCALE_CFG_ENABLED_MASK | \
+ ((er_index) << BW_SCALE_CFG_ER_ID_SHIFT) & BW_SCALE_CFG_ER_ID_MASK)
+
+#define MHI_BW_SCALE_RESULT(status, seq) ((status & 0xF) << 8 | (seq & 0xFF))
+#define MHI_BW_SCALE_NACK 0xF
+
enum MHI_ER_TYPE {
MHI_ER_TYPE_INVALID = 0x0,
MHI_ER_TYPE_VALID = 0x1,
};
+enum mhi_er_priority {
+ MHI_ER_PRIORITY_HIGH,
+ MHI_ER_PRIORITY_MEDIUM,
+ MHI_ER_PRIORITY_LOW,
+};
+
+#define IS_MHI_ER_PRIORITY_LOW(ev) (ev->priority >= MHI_ER_PRIORITY_LOW)
+#define IS_MHI_ER_PRIORITY_HIGH(ev) (ev->priority == MHI_ER_PRIORITY_HIGH)
+
enum mhi_er_data_type {
MHI_ER_DATA_ELEMENT_TYPE,
MHI_ER_CTRL_ELEMENT_TYPE,
MHI_ER_TSYNC_ELEMENT_TYPE,
- MHI_ER_DATA_TYPE_MAX = MHI_ER_TSYNC_ELEMENT_TYPE,
+ MHI_ER_BW_SCALE_ELEMENT_TYPE,
+ MHI_ER_DATA_TYPE_MAX = MHI_ER_BW_SCALE_ELEMENT_TYPE,
};
enum mhi_ch_ee_mask {
@@ -587,17 +619,19 @@ struct mhi_buf_info {
};
struct mhi_event {
+ struct list_head node;
u32 er_index;
u32 intmod;
u32 msi;
int chan; /* this event ring is dedicated to a channel */
- u32 priority;
+ enum mhi_er_priority priority;
enum mhi_er_data_type data_type;
struct mhi_ring ring;
struct db_cfg db_cfg;
bool hw_ring;
bool cl_manage;
bool offload_ev; /* managed by a device driver */
+ bool request_irq; /* has dedicated interrupt handler */
spinlock_t lock;
struct mhi_chan *mhi_chan; /* dedicated to channel */
struct tasklet_struct task;
@@ -700,6 +734,7 @@ int mhi_queue_state_transition(struct mhi_controller *mhi_cntrl,
void mhi_pm_st_worker(struct work_struct *work);
void mhi_fw_load_worker(struct work_struct *work);
void mhi_pm_sys_err_worker(struct work_struct *work);
+void mhi_low_priority_worker(struct work_struct *work);
int mhi_ready_state_transition(struct mhi_controller *mhi_cntrl);
void mhi_ctrl_ev_task(unsigned long data);
int mhi_pm_m0_transition(struct mhi_controller *mhi_cntrl);
@@ -712,6 +747,8 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl,
struct mhi_event *mhi_event, u32 event_quota);
int mhi_process_tsync_event_ring(struct mhi_controller *mhi_cntrl,
struct mhi_event *mhi_event, u32 event_quota);
+int mhi_process_bw_scale_ev_ring(struct mhi_controller *mhi_cntrl,
+ struct mhi_event *mhi_event, u32 event_quota);
int mhi_send_cmd(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan,
enum MHI_CMD cmd);
int __mhi_device_get_sync(struct mhi_controller *mhi_cntrl);
@@ -760,6 +797,7 @@ void mhi_ring_chan_db(struct mhi_controller *mhi_cntrl,
struct mhi_chan *mhi_chan);
int mhi_get_capability_offset(struct mhi_controller *mhi_cntrl, u32 capability,
u32 *offset);
+void *mhi_to_virtual(struct mhi_ring *ring, dma_addr_t addr);
int mhi_init_timesync(struct mhi_controller *mhi_cntrl);
int mhi_create_timesync_sysfs(struct mhi_controller *mhi_cntrl);
void mhi_destroy_timesync(struct mhi_controller *mhi_cntrl);
diff --git a/drivers/bus/mhi/core/mhi_main.c b/drivers/bus/mhi/core/mhi_main.c
index 7eb387d..8e1e2fd 100644
--- a/drivers/bus/mhi/core/mhi_main.c
+++ b/drivers/bus/mhi/core/mhi_main.c
@@ -81,7 +81,9 @@ int mhi_get_capability_offset(struct mhi_controller *mhi_cntrl,
if (ret)
return ret;
- *offset += next_offset;
+ *offset = next_offset;
+ if (*offset >= MHI_REG_SIZE)
+ return -ENXIO;
} while (next_offset);
return -ENXIO;
@@ -255,7 +257,7 @@ static int get_nr_avail_ring_elements(struct mhi_controller *mhi_cntrl,
return nr_el;
}
-static void *mhi_to_virtual(struct mhi_ring *ring, dma_addr_t addr)
+void *mhi_to_virtual(struct mhi_ring *ring, dma_addr_t addr)
{
return (addr - ring->iommu_base) + ring->base;
}
@@ -1133,25 +1135,6 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl,
local_rp->ptr, local_rp->dword[0], local_rp->dword[1]);
switch (type) {
- case MHI_PKT_TYPE_BW_REQ_EVENT:
- {
- struct mhi_link_info *link_info;
-
- link_info = &mhi_cntrl->mhi_link_info;
- write_lock_irq(&mhi_cntrl->pm_lock);
- link_info->target_link_speed =
- MHI_TRE_GET_EV_LINKSPEED(local_rp);
- link_info->target_link_width =
- MHI_TRE_GET_EV_LINKWIDTH(local_rp);
- write_unlock_irq(&mhi_cntrl->pm_lock);
- MHI_VERB(
- "Received BW_REQ with link speed:0x%x width:0x%x\n",
- link_info->target_link_speed,
- link_info->target_link_width);
- mhi_cntrl->status_cb(mhi_cntrl, mhi_cntrl->priv_data,
- MHI_CB_BW_REQ);
- break;
- }
case MHI_PKT_TYPE_STATE_CHANGE_EVENT:
{
enum mhi_dev_state new_state;
@@ -1241,7 +1224,7 @@ int mhi_process_ctrl_ev_ring(struct mhi_controller *mhi_cntrl,
break;
}
default:
- MHI_ASSERT(1, "Unsupported ev type");
+ MHI_ERR("Unhandled Event: 0x%x\n", type);
break;
}
@@ -1346,7 +1329,7 @@ int mhi_process_tsync_event_ring(struct mhi_controller *mhi_cntrl,
MHI_ASSERT(type != MHI_PKT_TYPE_TSYNC_EVENT, "!TSYNC event");
- sequence = MHI_TRE_GET_EV_SEQ(local_rp);
+ sequence = MHI_TRE_GET_EV_TSYNC_SEQ(local_rp);
remote_time = MHI_TRE_GET_EV_TIME(local_rp);
do {
@@ -1392,6 +1375,94 @@ int mhi_process_tsync_event_ring(struct mhi_controller *mhi_cntrl,
return count;
}
+int mhi_process_bw_scale_ev_ring(struct mhi_controller *mhi_cntrl,
+ struct mhi_event *mhi_event,
+ u32 event_quota)
+{
+ struct mhi_tre *dev_rp;
+ struct mhi_ring *ev_ring = &mhi_event->ring;
+ struct mhi_event_ctxt *er_ctxt =
+ &mhi_cntrl->mhi_ctxt->er_ctxt[mhi_event->er_index];
+ struct mhi_link_info link_info, *cur_info = &mhi_cntrl->mhi_link_info;
+ int result, ret = 0;
+
+ mutex_lock(&mhi_cntrl->pm_mutex);
+
+ if (unlikely(MHI_EVENT_ACCESS_INVALID(mhi_cntrl->pm_state))) {
+ MHI_LOG("No EV access, PM_STATE:%s\n",
+ to_mhi_pm_state_str(mhi_cntrl->pm_state));
+ ret = -EIO;
+ goto exit_bw_process;
+ }
+
+ /*
+ * BW change is not process during suspend since we're suspending link,
+ * host will process it during resume
+ */
+ if (MHI_PM_IN_SUSPEND_STATE(mhi_cntrl->pm_state)) {
+ ret = -EACCES;
+ goto exit_bw_process;
+ }
+
+ spin_lock_bh(&mhi_event->lock);
+ dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp);
+
+ if (ev_ring->rp == dev_rp) {
+ spin_unlock_bh(&mhi_event->lock);
+ goto exit_bw_process;
+ }
+
+ /* if rp points to base, we need to wrap it around */
+ if (dev_rp == ev_ring->base)
+ dev_rp = ev_ring->base + ev_ring->len;
+ dev_rp--;
+
+ MHI_ASSERT(MHI_TRE_GET_EV_TYPE(dev_rp) != MHI_PKT_TYPE_BW_REQ_EVENT,
+ "!BW SCALE REQ event");
+
+ link_info.target_link_speed = MHI_TRE_GET_EV_LINKSPEED(dev_rp);
+ link_info.target_link_width = MHI_TRE_GET_EV_LINKWIDTH(dev_rp);
+ link_info.sequence_num = MHI_TRE_GET_EV_BW_REQ_SEQ(dev_rp);
+
+ MHI_VERB("Received BW_REQ with seq:%d link speed:0x%x width:0x%x\n",
+ link_info.sequence_num,
+ link_info.target_link_speed,
+ link_info.target_link_width);
+
+ /* fast forward to currently processed element and recycle er */
+ ev_ring->rp = dev_rp;
+ ev_ring->wp = dev_rp - 1;
+ if (ev_ring->wp < ev_ring->base)
+ ev_ring->wp = ev_ring->base + ev_ring->len - ev_ring->el_size;
+ mhi_recycle_ev_ring_element(mhi_cntrl, ev_ring);
+
+ read_lock_bh(&mhi_cntrl->pm_lock);
+ if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl)))
+ mhi_ring_er_db(mhi_event);
+ read_unlock_bh(&mhi_cntrl->pm_lock);
+ spin_unlock_bh(&mhi_event->lock);
+
+ ret = mhi_cntrl->bw_scale(mhi_cntrl, &link_info);
+ if (!ret)
+ *cur_info = link_info;
+
+ result = ret ? MHI_BW_SCALE_NACK : 0;
+
+ read_lock_bh(&mhi_cntrl->pm_lock);
+ if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl)))
+ mhi_write_reg(mhi_cntrl, mhi_cntrl->bw_scale_db, 0,
+ MHI_BW_SCALE_RESULT(result,
+ link_info.sequence_num));
+ read_unlock_bh(&mhi_cntrl->pm_lock);
+
+exit_bw_process:
+ MHI_VERB("exit er_index:%u\n", mhi_event->er_index);
+
+ mutex_unlock(&mhi_cntrl->pm_mutex);
+
+ return ret;
+}
+
void mhi_ev_task(unsigned long data)
{
struct mhi_event *mhi_event = (struct mhi_event *)data;
@@ -1471,7 +1542,13 @@ irqreturn_t mhi_msi_handlr(int irq_number, void *dev)
if (mhi_dev)
mhi_dev->status_cb(mhi_dev, MHI_CB_PENDING_DATA);
- } else
+
+ return IRQ_HANDLED;
+ }
+
+ if (IS_MHI_ER_PRIORITY_HIGH(mhi_event))
+ tasklet_hi_schedule(&mhi_event->task);
+ else
tasklet_schedule(&mhi_event->task);
return IRQ_HANDLED;
@@ -1541,6 +1618,8 @@ irqreturn_t mhi_intvec_handlr(int irq_number, void *dev)
wake_up_all(&mhi_cntrl->state_event);
MHI_VERB("Exit\n");
+ schedule_work(&mhi_cntrl->low_priority_worker);
+
return IRQ_WAKE_THREAD;
}
diff --git a/drivers/bus/mhi/core/mhi_pm.c b/drivers/bus/mhi/core/mhi_pm.c
index e70cc65..b951f4e 100644
--- a/drivers/bus/mhi/core/mhi_pm.c
+++ b/drivers/bus/mhi/core/mhi_pm.c
@@ -589,7 +589,7 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl,
MHI_LOG("Waiting for all pending event ring processing to complete\n");
mhi_event = mhi_cntrl->mhi_event;
for (i = 0; i < mhi_cntrl->total_ev_rings; i++, mhi_event++) {
- if (mhi_event->offload_ev)
+ if (!mhi_event->request_irq)
continue;
tasklet_kill(&mhi_event->task);
}
@@ -608,6 +608,7 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl,
wake_up_all(&mhi_cntrl->state_event);
flush_work(&mhi_cntrl->st_worker);
flush_work(&mhi_cntrl->fw_worker);
+ flush_work(&mhi_cntrl->low_priority_worker);
mutex_lock(&mhi_cntrl->pm_mutex);
@@ -720,6 +721,44 @@ int mhi_queue_state_transition(struct mhi_controller *mhi_cntrl,
return 0;
}
+static void mhi_low_priority_events_pending(struct mhi_controller *mhi_cntrl)
+{
+ struct mhi_event *mhi_event;
+
+ list_for_each_entry(mhi_event, &mhi_cntrl->lp_ev_rings, node) {
+ struct mhi_event_ctxt *er_ctxt =
+ &mhi_cntrl->mhi_ctxt->er_ctxt[mhi_event->er_index];
+ struct mhi_ring *ev_ring = &mhi_event->ring;
+
+ spin_lock_bh(&mhi_event->lock);
+ if (ev_ring->rp != mhi_to_virtual(ev_ring, er_ctxt->rp)) {
+ schedule_work(&mhi_cntrl->low_priority_worker);
+ spin_unlock_bh(&mhi_event->lock);
+ break;
+ }
+ spin_unlock_bh(&mhi_event->lock);
+ }
+}
+
+void mhi_low_priority_worker(struct work_struct *work)
+{
+ struct mhi_controller *mhi_cntrl = container_of(work,
+ struct mhi_controller,
+ low_priority_worker);
+ struct mhi_event *mhi_event;
+
+ MHI_VERB("Enter with pm_state:%s MHI_STATE:%s ee:%s\n",
+ to_mhi_pm_state_str(mhi_cntrl->pm_state),
+ TO_MHI_STATE_STR(mhi_cntrl->dev_state),
+ TO_MHI_EXEC_STR(mhi_cntrl->ee));
+
+ /* check low priority event rings and process events */
+ list_for_each_entry(mhi_event, &mhi_cntrl->lp_ev_rings, node) {
+ if (MHI_IN_MISSION_MODE(mhi_cntrl->ee))
+ mhi_event->process_event(mhi_cntrl, mhi_event, U32_MAX);
+ }
+}
+
void mhi_pm_sys_err_worker(struct work_struct *work)
{
struct mhi_controller *mhi_cntrl = container_of(work,
@@ -904,6 +943,9 @@ void mhi_control_error(struct mhi_controller *mhi_cntrl)
goto exit_control_error;
}
+ /* notify waiters to bail out early since MHI has entered ERROR state */
+ wake_up_all(&mhi_cntrl->state_event);
+
/* start notifying all clients who request early notification */
device_for_each_child(mhi_cntrl->dev, NULL, mhi_early_notify_device);
@@ -1241,6 +1283,14 @@ int mhi_pm_resume(struct mhi_controller *mhi_cntrl)
return -EIO;
}
+ /*
+ * If MHI on host is in suspending/suspended state, we do not process
+ * any low priority requests, for example, bandwidth scaling events
+ * from the device. Check for low priority event rings and handle the
+ * pending events upon resume.
+ */
+ mhi_low_priority_events_pending(mhi_cntrl);
+
return 0;
}
@@ -1303,12 +1353,15 @@ int mhi_pm_fast_resume(struct mhi_controller *mhi_cntrl, bool notify_client)
*/
mhi_event = mhi_cntrl->mhi_event;
for (i = 0; i < mhi_cntrl->total_ev_rings; i++, mhi_event++) {
- if (mhi_event->offload_ev)
+ if (!mhi_event->request_irq)
continue;
mhi_msi_handlr(0, mhi_event);
}
+ /* schedules worker if any low priority events need to be handled */
+ mhi_low_priority_events_pending(mhi_cntrl);
+
MHI_LOG("Exit with pm_state:%s dev_state:%s\n",
to_mhi_pm_state_str(mhi_cntrl->pm_state),
TO_MHI_STATE_STR(mhi_cntrl->dev_state));
diff --git a/drivers/bus/mhi/devices/mhi_netdev.c b/drivers/bus/mhi/devices/mhi_netdev.c
index ce1e28f..772964a 100644
--- a/drivers/bus/mhi/devices/mhi_netdev.c
+++ b/drivers/bus/mhi/devices/mhi_netdev.c
@@ -14,6 +14,7 @@
#include <linux/errno.h>
#include <linux/of_device.h>
#include <linux/rtnetlink.h>
+#include <linux/kthread.h>
#include <linux/mhi.h>
#define MHI_NETDEV_DRIVER_NAME "mhi_netdev"
@@ -80,6 +81,7 @@ struct mhi_netdev {
int alias;
struct mhi_device *mhi_dev;
struct mhi_netdev *rsc_dev; /* rsc linked node */
+ struct mhi_netdev *rsc_parent;
bool is_rsc_dev;
int wake;
@@ -89,16 +91,26 @@ struct mhi_netdev {
struct napi_struct *napi;
struct net_device *ndev;
- struct mhi_netbuf **netbuf_pool;
- int pool_size; /* must be power of 2 */
- int current_index;
+ struct list_head *recycle_pool;
+ int pool_size;
bool chain_skb;
struct mhi_net_chain *chain;
+ struct task_struct *alloc_task;
+ wait_queue_head_t alloc_event;
+ int bg_pool_limit; /* minimum pool size */
+ int bg_pool_size; /* current size of the pool */
+ struct list_head *bg_pool;
+ spinlock_t bg_lock; /* lock to access list */
+
+
struct dentry *dentry;
enum MHI_DEBUG_LEVEL msg_lvl;
enum MHI_DEBUG_LEVEL ipc_log_lvl;
void *ipc_log;
+
+ /* debug stats */
+ u32 abuffers, kbuffers, rbuffers;
};
struct mhi_netdev_priv {
@@ -111,6 +123,7 @@ struct mhi_netdev_priv {
*/
struct mhi_netbuf {
struct mhi_buf mhi_buf; /* this must be first element */
+ bool recycle;
void (*unmap)(struct device *dev, dma_addr_t addr, size_t size,
enum dma_data_direction dir);
};
@@ -147,7 +160,7 @@ static struct mhi_netbuf *mhi_netdev_alloc(struct device *dev,
struct mhi_buf *mhi_buf;
void *vaddr;
- page = __dev_alloc_pages(gfp, order);
+ page = __dev_alloc_pages(gfp | __GFP_NOMEMALLOC, order);
if (!page)
return NULL;
@@ -155,11 +168,15 @@ static struct mhi_netbuf *mhi_netdev_alloc(struct device *dev,
/* we going to use the end of page to store cached data */
netbuf = vaddr + (PAGE_SIZE << order) - sizeof(*netbuf);
-
+ netbuf->recycle = false;
mhi_buf = (struct mhi_buf *)netbuf;
mhi_buf->page = page;
mhi_buf->buf = vaddr;
mhi_buf->len = (void *)netbuf - vaddr;
+
+ if (!dev)
+ return netbuf;
+
mhi_buf->dma_addr = dma_map_page(dev, page, 0, mhi_buf->len,
DMA_FROM_DEVICE);
if (dma_mapping_error(dev, mhi_buf->dma_addr)) {
@@ -178,9 +195,10 @@ static void mhi_netdev_unmap_page(struct device *dev,
dma_unmap_page(dev, dma_addr, len, dir);
}
-static int mhi_netdev_tmp_alloc(struct mhi_netdev *mhi_netdev, int nr_tre)
+static int mhi_netdev_tmp_alloc(struct mhi_netdev *mhi_netdev,
+ struct mhi_device *mhi_dev,
+ int nr_tre)
{
- struct mhi_device *mhi_dev = mhi_netdev->mhi_dev;
struct device *dev = mhi_dev->dev.parent;
const u32 order = mhi_netdev->order;
int i, ret;
@@ -204,21 +222,73 @@ static int mhi_netdev_tmp_alloc(struct mhi_netdev *mhi_netdev, int nr_tre)
__free_pages(mhi_buf->page, order);
return ret;
}
+ mhi_netdev->abuffers++;
}
return 0;
}
-static void mhi_netdev_queue(struct mhi_netdev *mhi_netdev)
+static int mhi_netdev_queue_bg_pool(struct mhi_netdev *mhi_netdev,
+ struct mhi_device *mhi_dev,
+ int nr_tre)
{
- struct mhi_device *mhi_dev = mhi_netdev->mhi_dev;
+ struct device *dev = mhi_dev->dev.parent;
+ int i, ret;
+ LIST_HEAD(head);
+
+ spin_lock_bh(&mhi_netdev->bg_lock);
+ list_splice_init(mhi_netdev->bg_pool, &head);
+ spin_unlock_bh(&mhi_netdev->bg_lock);
+
+ for (i = 0; i < nr_tre; i++) {
+ struct mhi_buf *mhi_buf =
+ list_first_entry_or_null(&head, struct mhi_buf, node);
+ struct mhi_netbuf *netbuf = (struct mhi_netbuf *)mhi_buf;
+
+ if (!mhi_buf)
+ break;
+
+ mhi_buf->dma_addr = dma_map_page(dev, mhi_buf->page, 0,
+ mhi_buf->len, DMA_FROM_DEVICE);
+ if (dma_mapping_error(dev, mhi_buf->dma_addr))
+ break;
+
+ netbuf->unmap = mhi_netdev_unmap_page;
+ ret = mhi_queue_transfer(mhi_dev, DMA_FROM_DEVICE, mhi_buf,
+ mhi_buf->len, MHI_EOT);
+ if (unlikely(ret)) {
+ MSG_ERR("Failed to queue transfer, ret:%d\n", ret);
+ mhi_netdev_unmap_page(dev, mhi_buf->dma_addr,
+ mhi_buf->len, DMA_FROM_DEVICE);
+ break;
+ }
+ list_del(&mhi_buf->node);
+ mhi_netdev->kbuffers++;
+ }
+
+ /* add remaining buffers back to main pool */
+ spin_lock_bh(&mhi_netdev->bg_lock);
+ list_splice(&head, mhi_netdev->bg_pool);
+ mhi_netdev->bg_pool_size -= i;
+ spin_unlock_bh(&mhi_netdev->bg_lock);
+
+
+ /* wake up the bg thread to allocate more buffers */
+ wake_up_interruptible(&mhi_netdev->alloc_event);
+
+ return i;
+}
+
+static void mhi_netdev_queue(struct mhi_netdev *mhi_netdev,
+ struct mhi_device *mhi_dev)
+{
struct device *dev = mhi_dev->dev.parent;
struct mhi_netbuf *netbuf;
struct mhi_buf *mhi_buf;
- struct mhi_netbuf **netbuf_pool = mhi_netdev->netbuf_pool;
+ struct list_head *pool = mhi_netdev->recycle_pool;
int nr_tre = mhi_get_no_free_descriptors(mhi_dev, DMA_FROM_DEVICE);
- int i, peak, cur_index, ret;
- const int pool_size = mhi_netdev->pool_size - 1, max_peak = 4;
+ int i, ret;
+ const int max_peek = 4;
MSG_VERB("Enter free_desc:%d\n", nr_tre);
@@ -227,23 +297,21 @@ static void mhi_netdev_queue(struct mhi_netdev *mhi_netdev)
/* try going thru reclaim pool first */
for (i = 0; i < nr_tre; i++) {
- /* peak for the next buffer, we going to peak several times,
+ /* peek for the next buffer, we going to peak several times,
* and we going to give up if buffers are not yet free
*/
- cur_index = mhi_netdev->current_index;
+ int peek = 0;
+
netbuf = NULL;
- for (peak = 0; peak < max_peak; peak++) {
- struct mhi_netbuf *tmp = netbuf_pool[cur_index];
-
- mhi_buf = &tmp->mhi_buf;
-
- cur_index = (cur_index + 1) & pool_size;
-
+ list_for_each_entry(mhi_buf, pool, node) {
/* page == 1 idle, buffer is free to reclaim */
if (page_ref_count(mhi_buf->page) == 1) {
- netbuf = tmp;
+ netbuf = (struct mhi_netbuf *)mhi_buf;
break;
}
+
+ if (peek++ >= max_peek)
+ break;
}
/* could not find a free buffer */
@@ -254,6 +322,7 @@ static void mhi_netdev_queue(struct mhi_netdev *mhi_netdev)
* with buffer, the buffer won't be freed
*/
page_ref_inc(mhi_buf->page);
+ list_del(&mhi_buf->node);
dma_sync_single_for_device(dev, mhi_buf->dma_addr, mhi_buf->len,
DMA_FROM_DEVICE);
ret = mhi_queue_transfer(mhi_dev, DMA_FROM_DEVICE, mhi_buf,
@@ -263,30 +332,36 @@ static void mhi_netdev_queue(struct mhi_netdev *mhi_netdev)
netbuf->unmap(dev, mhi_buf->dma_addr, mhi_buf->len,
DMA_FROM_DEVICE);
page_ref_dec(mhi_buf->page);
+ list_add(&mhi_buf->node, pool);
return;
}
- mhi_netdev->current_index = cur_index;
+ mhi_netdev->rbuffers++;
}
+ /* recycling did not work, buffers are still busy use bg pool */
+ if (i < nr_tre)
+ i += mhi_netdev_queue_bg_pool(mhi_netdev, mhi_dev, nr_tre - i);
+
/* recyling did not work, buffers are still busy allocate temp pkts */
if (i < nr_tre)
- mhi_netdev_tmp_alloc(mhi_netdev, nr_tre - i);
+ mhi_netdev_tmp_alloc(mhi_netdev, mhi_dev, nr_tre - i);
}
/* allocating pool of memory */
static int mhi_netdev_alloc_pool(struct mhi_netdev *mhi_netdev)
{
int i;
- struct mhi_netbuf *netbuf, **netbuf_pool;
- struct mhi_buf *mhi_buf;
+ struct mhi_netbuf *netbuf;
+ struct mhi_buf *mhi_buf, *tmp;
const u32 order = mhi_netdev->order;
struct device *dev = mhi_netdev->mhi_dev->dev.parent;
+ struct list_head *pool = kmalloc(sizeof(*pool), GFP_KERNEL);
- netbuf_pool = kmalloc_array(mhi_netdev->pool_size, sizeof(*netbuf_pool),
- GFP_KERNEL);
- if (!netbuf_pool)
+ if (!pool)
return -ENOMEM;
+ INIT_LIST_HEAD(pool);
+
for (i = 0; i < mhi_netdev->pool_size; i++) {
/* allocate paged data */
netbuf = mhi_netdev_alloc(dev, GFP_KERNEL, order);
@@ -294,44 +369,100 @@ static int mhi_netdev_alloc_pool(struct mhi_netdev *mhi_netdev)
goto error_alloc_page;
netbuf->unmap = dma_sync_single_for_cpu;
- netbuf_pool[i] = netbuf;
+ netbuf->recycle = true;
+ mhi_buf = (struct mhi_buf *)netbuf;
+ list_add(&mhi_buf->node, pool);
}
- mhi_netdev->netbuf_pool = netbuf_pool;
+ mhi_netdev->recycle_pool = pool;
return 0;
error_alloc_page:
- for (--i; i >= 0; i--) {
- netbuf = netbuf_pool[i];
- mhi_buf = &netbuf->mhi_buf;
+ list_for_each_entry_safe(mhi_buf, tmp, pool, node) {
+ list_del(&mhi_buf->node);
dma_unmap_page(dev, mhi_buf->dma_addr, mhi_buf->len,
DMA_FROM_DEVICE);
__free_pages(mhi_buf->page, order);
}
- kfree(netbuf_pool);
+ kfree(pool);
return -ENOMEM;
}
static void mhi_netdev_free_pool(struct mhi_netdev *mhi_netdev)
{
- int i;
- struct mhi_netbuf *netbuf, **netbuf_pool = mhi_netdev->netbuf_pool;
struct device *dev = mhi_netdev->mhi_dev->dev.parent;
- struct mhi_buf *mhi_buf;
+ struct mhi_buf *mhi_buf, *tmp;
- for (i = 0; i < mhi_netdev->pool_size; i++) {
- netbuf = netbuf_pool[i];
- mhi_buf = &netbuf->mhi_buf;
+ list_for_each_entry_safe(mhi_buf, tmp, mhi_netdev->recycle_pool, node) {
+ list_del(&mhi_buf->node);
dma_unmap_page(dev, mhi_buf->dma_addr, mhi_buf->len,
DMA_FROM_DEVICE);
__free_pages(mhi_buf->page, mhi_netdev->order);
}
- kfree(mhi_netdev->netbuf_pool);
- mhi_netdev->netbuf_pool = NULL;
+ kfree(mhi_netdev->recycle_pool);
+
+ /* free the bg pool */
+ list_for_each_entry_safe(mhi_buf, tmp, mhi_netdev->bg_pool, node) {
+ list_del(&mhi_buf->node);
+ __free_pages(mhi_buf->page, mhi_netdev->order);
+ mhi_netdev->bg_pool_size--;
+ }
+}
+
+static int mhi_netdev_alloc_thread(void *data)
+{
+ struct mhi_netdev *mhi_netdev = data;
+ struct mhi_netbuf *netbuf;
+ struct mhi_buf *mhi_buf, *tmp_buf;
+ const u32 order = mhi_netdev->order;
+ LIST_HEAD(head);
+
+ while (!kthread_should_stop()) {
+ while (mhi_netdev->bg_pool_size <= mhi_netdev->bg_pool_limit) {
+ int buffers = 0, i;
+
+ /* do a bulk allocation */
+ for (i = 0; i < NAPI_POLL_WEIGHT; i++) {
+ if (kthread_should_stop())
+ goto exit_alloc;
+
+ netbuf = mhi_netdev_alloc(NULL, GFP_KERNEL,
+ order);
+ if (!netbuf)
+ continue;
+
+ mhi_buf = (struct mhi_buf *)netbuf;
+ list_add(&mhi_buf->node, &head);
+ buffers++;
+ }
+
+ /* add the list to main pool */
+ spin_lock_bh(&mhi_netdev->bg_lock);
+ list_splice_init(&head, mhi_netdev->bg_pool);
+ mhi_netdev->bg_pool_size += buffers;
+ spin_unlock_bh(&mhi_netdev->bg_lock);
+ }
+
+ /* replenish the ring */
+ napi_schedule(mhi_netdev->napi);
+
+ /* wait for buffers to run low or thread to stop */
+ wait_event_interruptible(mhi_netdev->alloc_event,
+ kthread_should_stop() ||
+ mhi_netdev->bg_pool_size <= mhi_netdev->bg_pool_limit);
+ }
+
+exit_alloc:
+ list_for_each_entry_safe(mhi_buf, tmp_buf, &head, node) {
+ list_del(&mhi_buf->node);
+ __free_pages(mhi_buf->page, order);
+ }
+
+ return 0;
}
static int mhi_netdev_poll(struct napi_struct *napi, int budget)
@@ -361,10 +492,10 @@ static int mhi_netdev_poll(struct napi_struct *napi, int budget)
}
/* queue new buffers */
- mhi_netdev_queue(mhi_netdev);
+ mhi_netdev_queue(mhi_netdev, mhi_dev);
if (rsc_dev)
- mhi_netdev_queue(rsc_dev);
+ mhi_netdev_queue(mhi_netdev, rsc_dev->mhi_dev);
/* complete work if # of packet processed less than allocated budget */
if (rx_work < budget)
@@ -658,6 +789,8 @@ static void mhi_netdev_xfer_dl_cb(struct mhi_device *mhi_dev,
struct mhi_net_chain *chain = mhi_netdev->chain;
netbuf->unmap(dev, mhi_buf->dma_addr, mhi_buf->len, DMA_FROM_DEVICE);
+ if (likely(netbuf->recycle))
+ list_add_tail(&mhi_buf->node, mhi_netdev->recycle_pool);
/* modem is down, drop the buffer */
if (mhi_result->transaction_status == -ENOTCONN) {
@@ -708,6 +841,31 @@ static void mhi_netdev_status_cb(struct mhi_device *mhi_dev, enum MHI_CB mhi_cb)
struct dentry *dentry;
+static int mhi_netdev_debugfs_stats_show(struct seq_file *m, void *d)
+{
+ struct mhi_netdev *mhi_netdev = m->private;
+
+ seq_printf(m,
+ "mru:%u order:%u pool_size:%d, bg_pool_size:%d bg_pool_limit:%d abuf:%u kbuf:%u rbuf:%u\n",
+ mhi_netdev->mru, mhi_netdev->order, mhi_netdev->pool_size,
+ mhi_netdev->bg_pool_size, mhi_netdev->bg_pool_limit,
+ mhi_netdev->abuffers, mhi_netdev->kbuffers,
+ mhi_netdev->rbuffers);
+
+ return 0;
+}
+
+static int mhi_netdev_debugfs_stats_open(struct inode *inode, struct file *fp)
+{
+ return single_open(fp, mhi_netdev_debugfs_stats_show, inode->i_private);
+}
+
+static const struct file_operations debugfs_stats = {
+ .open = mhi_netdev_debugfs_stats_open,
+ .release = single_release,
+ .read = seq_read,
+};
+
static void mhi_netdev_create_debugfs(struct mhi_netdev *mhi_netdev)
{
char node_name[32];
@@ -724,6 +882,9 @@ static void mhi_netdev_create_debugfs(struct mhi_netdev *mhi_netdev)
mhi_netdev->dentry = debugfs_create_dir(node_name, dentry);
if (IS_ERR_OR_NULL(mhi_netdev->dentry))
return;
+
+ debugfs_create_file_unsafe("stats", 0444, mhi_netdev->dentry,
+ mhi_netdev, &debugfs_stats);
}
static void mhi_netdev_create_debugfs_dir(void)
@@ -755,12 +916,12 @@ static void mhi_netdev_remove(struct mhi_device *mhi_dev)
return;
}
+ kthread_stop(mhi_netdev->alloc_task);
netif_stop_queue(mhi_netdev->ndev);
napi_disable(mhi_netdev->napi);
unregister_netdev(mhi_netdev->ndev);
netif_napi_del(mhi_netdev->napi);
free_netdev(mhi_netdev->ndev);
- mhi_netdev_free_pool(mhi_netdev);
if (!IS_ERR_OR_NULL(mhi_netdev->dentry))
debugfs_remove_recursive(mhi_netdev->dentry);
@@ -782,6 +943,9 @@ static void mhi_netdev_clone_dev(struct mhi_netdev *mhi_netdev,
mhi_netdev->ipc_log_lvl = parent->ipc_log_lvl;
mhi_netdev->is_rsc_dev = true;
mhi_netdev->chain = parent->chain;
+ mhi_netdev->rsc_parent = parent;
+ mhi_netdev->recycle_pool = parent->recycle_pool;
+ mhi_netdev->bg_pool = parent->bg_pool;
}
static int mhi_netdev_probe(struct mhi_device *mhi_dev,
@@ -803,6 +967,13 @@ static int mhi_netdev_probe(struct mhi_device *mhi_dev,
if (!mhi_netdev)
return -ENOMEM;
+ /* move mhi channels to start state */
+ ret = mhi_prepare_for_transfer(mhi_dev);
+ if (ret) {
+ MSG_ERR("Failed to start channels ret %d\n", ret);
+ return ret;
+ }
+
mhi_netdev->mhi_dev = mhi_dev;
mhi_device_set_devdata(mhi_dev, mhi_netdev);
@@ -850,6 +1021,38 @@ static int mhi_netdev_probe(struct mhi_device *mhi_dev,
if (ret)
return ret;
+ /* setup pool size ~2x ring length*/
+ nr_tre = mhi_get_no_free_descriptors(mhi_dev, DMA_FROM_DEVICE);
+ mhi_netdev->pool_size = 1 << __ilog2_u32(nr_tre);
+ if (nr_tre > mhi_netdev->pool_size)
+ mhi_netdev->pool_size <<= 1;
+ mhi_netdev->pool_size <<= 1;
+
+ /* if we expect child device to share then double the pool */
+ if (of_parse_phandle(of_node, "mhi,rsc-child", 0))
+ mhi_netdev->pool_size <<= 1;
+
+ /* allocate memory pool */
+ ret = mhi_netdev_alloc_pool(mhi_netdev);
+ if (ret)
+ return -ENOMEM;
+
+ /* create a background task to allocate memory */
+ mhi_netdev->bg_pool = kmalloc(sizeof(*mhi_netdev->bg_pool),
+ GFP_KERNEL);
+ if (!mhi_netdev->bg_pool)
+ return -ENOMEM;
+
+ init_waitqueue_head(&mhi_netdev->alloc_event);
+ INIT_LIST_HEAD(mhi_netdev->bg_pool);
+ spin_lock_init(&mhi_netdev->bg_lock);
+ mhi_netdev->bg_pool_limit = mhi_netdev->pool_size / 4;
+ mhi_netdev->alloc_task = kthread_run(mhi_netdev_alloc_thread,
+ mhi_netdev,
+ mhi_netdev->ndev->name);
+ if (IS_ERR(mhi_netdev->alloc_task))
+ return PTR_ERR(mhi_netdev->alloc_task);
+
/* create ipc log buffer */
snprintf(node_name, sizeof(node_name),
"%s_%04x_%02u.%02u.%02u_%u",
@@ -863,25 +1066,6 @@ static int mhi_netdev_probe(struct mhi_device *mhi_dev,
mhi_netdev_create_debugfs(mhi_netdev);
}
- /* move mhi channels to start state */
- ret = mhi_prepare_for_transfer(mhi_dev);
- if (ret) {
- MSG_ERR("Failed to start channels ret %d\n", ret);
- goto error_start;
- }
-
- /* setup pool size ~2x ring length*/
- nr_tre = mhi_get_no_free_descriptors(mhi_dev, DMA_FROM_DEVICE);
- mhi_netdev->pool_size = 1 << __ilog2_u32(nr_tre);
- if (nr_tre > mhi_netdev->pool_size)
- mhi_netdev->pool_size <<= 1;
- mhi_netdev->pool_size <<= 1;
-
- /* allocate memory pool */
- ret = mhi_netdev_alloc_pool(mhi_netdev);
- if (ret)
- goto error_start;
-
/* link child node with parent node if it's children dev */
if (p_netdev)
p_netdev->rsc_dev = mhi_netdev;
@@ -892,18 +1076,6 @@ static int mhi_netdev_probe(struct mhi_device *mhi_dev,
napi_schedule(mhi_netdev->napi);
return 0;
-
-error_start:
- if (phandle)
- return ret;
-
- netif_stop_queue(mhi_netdev->ndev);
- napi_disable(mhi_netdev->napi);
- unregister_netdev(mhi_netdev->ndev);
- netif_napi_del(mhi_netdev->napi);
- free_netdev(mhi_netdev->ndev);
-
- return ret;
}
static const struct mhi_device_id mhi_netdev_match_table[] = {
diff --git a/drivers/bus/mhi/devices/mhi_satellite.c b/drivers/bus/mhi/devices/mhi_satellite.c
index 33338f4..162d8a6 100644
--- a/drivers/bus/mhi/devices/mhi_satellite.c
+++ b/drivers/bus/mhi/devices/mhi_satellite.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2019, The Linux Foundation. All rights reserved.*/
-#include <linux/debugfs.h>
+#include <linux/async.h>
#include <linux/device.h>
#include <linux/dma-direction.h>
#include <linux/dma-mapping.h>
@@ -19,8 +19,6 @@
#define MHI_SAT_DRIVER_NAME "mhi_satellite"
-static bool mhi_sat_defer_init;
-
/* logging macros */
#define IPC_LOG_PAGES (10)
#define IPC_LOG_LVL (MHI_MSG_LVL_INFO)
@@ -147,17 +145,13 @@ enum mhi_ev_ccs {
/* satellite subsystem definitions */
enum subsys_id {
SUBSYS_ADSP,
- SUBSYS_CDSP,
SUBSYS_SLPI,
- SUBSYS_MODEM,
SUBSYS_MAX,
};
static const char * const subsys_names[SUBSYS_MAX] = {
[SUBSYS_ADSP] = "adsp",
- [SUBSYS_CDSP] = "cdsp",
[SUBSYS_SLPI] = "slpi",
- [SUBSYS_MODEM] = "modem",
};
struct mhi_sat_subsys {
@@ -235,6 +229,21 @@ struct mhi_sat_packet {
void *msg; /* incoming message */
};
+enum mhi_sat_state {
+ SAT_READY, /* initial state when device is presented to driver */
+ SAT_RUNNING, /* subsystem can communicate with the device */
+ SAT_DISCONNECTED, /* rpmsg link is down */
+ SAT_FATAL_DETECT, /* device is down as fatal error was detected early */
+ SAT_ERROR, /* device is down after error or graceful shutdown */
+ SAT_DISABLED, /* set if rpmsg link goes down after device is down */
+};
+
+#define MHI_SAT_ACTIVE(cntrl) (cntrl->state == SAT_RUNNING)
+#define MHI_SAT_FATAL_DETECT(cntrl) (cntrl->state == SAT_FATAL_DETECT)
+#define MHI_SAT_ALLOW_CONNECTION(cntrl) (cntrl->state == SAT_READY || \
+ cntrl->state == SAT_DISCONNECTED)
+#define MHI_SAT_IN_ERROR_STATE(cntrl) (cntrl->state >= SAT_FATAL_DETECT)
+
struct mhi_sat_cntrl {
struct list_head node;
@@ -250,6 +259,7 @@ struct mhi_sat_cntrl {
struct work_struct connect_work; /* subsystem connection worker */
struct work_struct process_work; /* incoming packets processor */
+ async_cookie_t error_cookie; /* synchronize device error handling */
/* mhi core/controller configurations */
u32 dev_id; /* unique device ID with BDF as per connection topology */
@@ -261,7 +271,8 @@ struct mhi_sat_cntrl {
int num_devices; /* mhi devices current count */
int max_devices; /* count of maximum devices for subsys/controller */
u16 seq; /* internal sequence number for all outgoing packets */
- bool active; /* flag set if hello packet/MHI_CFG event was sent */
+ enum mhi_sat_state state; /* controller state manager */
+ spinlock_t state_lock; /* lock to change controller state */
/* command completion variables */
u16 last_cmd_seq; /* sequence number of last sent command packet */
@@ -285,9 +296,6 @@ struct mhi_sat_driver {
struct mhi_sat_subsys *subsys; /* pointer to subsystem array */
unsigned int num_subsys;
-
- struct dentry *dentry; /* debugfs directory */
- bool deferred_init_done; /* flag for deferred init protection */
};
static struct mhi_sat_driver mhi_sat_driver;
@@ -566,6 +574,83 @@ static void mhi_sat_process_cmds(struct mhi_sat_cntrl *sat_cntrl,
}
}
+/* send sys_err command to subsystem if device asserts or is powered off */
+static void mhi_sat_send_sys_err(struct mhi_sat_cntrl *sat_cntrl)
+{
+ struct mhi_sat_subsys *subsys = sat_cntrl->subsys;
+ struct sat_tre *pkt;
+ void *msg;
+ int ret;
+
+ /* flush all pending work */
+ flush_work(&sat_cntrl->connect_work);
+ flush_work(&sat_cntrl->process_work);
+
+ msg = kmalloc(SAT_MSG_SIZE(1), GFP_KERNEL);
+
+ MHI_SAT_ASSERT(!msg, "Unable to malloc for SYS_ERR message!\n");
+ if (!msg)
+ return;
+
+ pkt = SAT_TRE_OFFSET(msg);
+ pkt->ptr = MHI_TRE_CMD_SYS_ERR_PTR;
+ pkt->dword[0] = MHI_TRE_CMD_SYS_ERR_D0;
+ pkt->dword[1] = MHI_TRE_CMD_SYS_ERR_D1;
+
+ mutex_lock(&sat_cntrl->cmd_wait_mutex);
+
+ ret = mhi_sat_send_msg(sat_cntrl, SAT_MSG_ID_CMD,
+ SAT_RESERVED_SEQ_NUM, msg,
+ SAT_MSG_SIZE(1));
+ kfree(msg);
+ if (ret) {
+ MHI_SAT_ERR("Failed to notify SYS_ERR cmd\n");
+ mutex_unlock(&sat_cntrl->cmd_wait_mutex);
+ return;
+ }
+
+ MHI_SAT_LOG("SYS_ERR command sent\n");
+
+ /* blocking call to wait for command completion event */
+ mhi_sat_wait_cmd_completion(sat_cntrl);
+
+ mutex_unlock(&sat_cntrl->cmd_wait_mutex);
+}
+
+static void mhi_sat_error_worker(void *data, async_cookie_t cookie)
+{
+ struct mhi_sat_cntrl *sat_cntrl = data;
+ struct mhi_sat_subsys *subsys = sat_cntrl->subsys;
+ struct sat_tre *pkt;
+ void *msg;
+ int ret;
+
+ MHI_SAT_LOG("Entered\n");
+
+ /* flush all pending work */
+ flush_work(&sat_cntrl->connect_work);
+ flush_work(&sat_cntrl->process_work);
+
+ msg = kmalloc(SAT_MSG_SIZE(1), GFP_KERNEL);
+
+ MHI_SAT_ASSERT(!msg, "Unable to malloc for SYS_ERR message!\n");
+ if (!msg)
+ return;
+
+ pkt = SAT_TRE_OFFSET(msg);
+ pkt->ptr = MHI_TRE_EVT_MHI_STATE_PTR;
+ pkt->dword[0] = MHI_TRE_EVT_MHI_STATE_D0(MHI_STATE_SYS_ERR);
+ pkt->dword[1] = MHI_TRE_EVT_MHI_STATE_D1;
+
+ ret = mhi_sat_send_msg(sat_cntrl, SAT_MSG_ID_EVT,
+ SAT_RESERVED_SEQ_NUM, msg,
+ SAT_MSG_SIZE(1));
+ kfree(msg);
+
+ MHI_SAT_LOG("SYS_ERROR state change event send %s!\n", ret ? "failure" :
+ "success");
+}
+
static void mhi_sat_process_worker(struct work_struct *work)
{
struct mhi_sat_cntrl *sat_cntrl = container_of(work,
@@ -588,6 +673,9 @@ static void mhi_sat_process_worker(struct work_struct *work)
list_del(&packet->node);
+ if (!MHI_SAT_ACTIVE(sat_cntrl))
+ goto process_next;
+
mhi_sat_process_cmds(sat_cntrl, hdr, pkt);
/* send response event(s) */
@@ -596,6 +684,7 @@ static void mhi_sat_process_worker(struct work_struct *work)
SAT_MSG_SIZE(SAT_TRE_NUM_PKTS(
hdr->payload_size)));
+process_next:
kfree(packet);
}
@@ -607,21 +696,26 @@ static void mhi_sat_connect_worker(struct work_struct *work)
struct mhi_sat_cntrl *sat_cntrl = container_of(work,
struct mhi_sat_cntrl, connect_work);
struct mhi_sat_subsys *subsys = sat_cntrl->subsys;
+ enum mhi_sat_state prev_state;
struct sat_tre *pkt;
void *msg;
int ret;
+ spin_lock_irq(&sat_cntrl->state_lock);
if (!subsys->rpdev || sat_cntrl->max_devices != sat_cntrl->num_devices
- || sat_cntrl->active)
+ || !(MHI_SAT_ALLOW_CONNECTION(sat_cntrl))) {
+ spin_unlock_irq(&sat_cntrl->state_lock);
return;
+ }
+ prev_state = sat_cntrl->state;
+ sat_cntrl->state = SAT_RUNNING;
+ spin_unlock_irq(&sat_cntrl->state_lock);
MHI_SAT_LOG("Entered\n");
msg = kmalloc(SAT_MSG_SIZE(3), GFP_ATOMIC);
if (!msg)
- return;
-
- sat_cntrl->active = true;
+ goto error_connect_work;
pkt = SAT_TRE_OFFSET(msg);
@@ -648,11 +742,18 @@ static void mhi_sat_connect_worker(struct work_struct *work)
kfree(msg);
if (ret) {
MHI_SAT_ERR("Failed to send hello packet:%d\n", ret);
- sat_cntrl->active = false;
- return;
+ goto error_connect_work;
}
MHI_SAT_LOG("Device 0x%x sent hello packet\n", sat_cntrl->dev_id);
+
+ return;
+
+error_connect_work:
+ spin_lock_irq(&sat_cntrl->state_lock);
+ if (MHI_SAT_ACTIVE(sat_cntrl))
+ sat_cntrl->state = prev_state;
+ spin_unlock_irq(&sat_cntrl->state_lock);
}
static void mhi_sat_process_events(struct mhi_sat_cntrl *sat_cntrl,
@@ -697,7 +798,7 @@ static int mhi_sat_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len,
}
/* Inactive controller cannot process incoming commands */
- if (unlikely(!sat_cntrl->active)) {
+ if (unlikely(!MHI_SAT_ACTIVE(sat_cntrl))) {
MHI_SAT_ERR("Message for inactive controller!\n");
return 0;
}
@@ -732,10 +833,21 @@ static void mhi_sat_rpmsg_remove(struct rpmsg_device *rpdev)
/* unprepare each controller/device from transfer */
mutex_lock(&subsys->cntrl_mutex);
list_for_each_entry(sat_cntrl, &subsys->cntrl_list, node) {
- if (!sat_cntrl->active)
- continue;
+ async_synchronize_cookie(sat_cntrl->error_cookie + 1);
- sat_cntrl->active = false;
+ spin_lock_irq(&sat_cntrl->state_lock);
+ /*
+ * move to disabled state if early error fatal is detected
+ * and rpmsg link goes down before device remove call from
+ * mhi is received
+ */
+ if (MHI_SAT_IN_ERROR_STATE(sat_cntrl)) {
+ sat_cntrl->state = SAT_DISABLED;
+ spin_unlock_irq(&sat_cntrl->state_lock);
+ continue;
+ }
+ sat_cntrl->state = SAT_DISCONNECTED;
+ spin_unlock_irq(&sat_cntrl->state_lock);
flush_work(&sat_cntrl->connect_work);
flush_work(&sat_cntrl->process_work);
@@ -814,6 +926,21 @@ static struct rpmsg_driver mhi_sat_rpmsg_driver = {
static void mhi_sat_dev_status_cb(struct mhi_device *mhi_dev,
enum MHI_CB mhi_cb)
{
+ struct mhi_sat_device *sat_dev = mhi_device_get_devdata(mhi_dev);
+ struct mhi_sat_cntrl *sat_cntrl = sat_dev->cntrl;
+ struct mhi_sat_subsys *subsys = sat_cntrl->subsys;
+ unsigned long flags;
+
+ if (mhi_cb != MHI_CB_FATAL_ERROR)
+ return;
+
+ MHI_SAT_LOG("Device fatal error detected\n");
+ spin_lock_irqsave(&sat_cntrl->state_lock, flags);
+ if (MHI_SAT_ACTIVE(sat_cntrl))
+ sat_cntrl->error_cookie = async_schedule(mhi_sat_error_worker,
+ sat_cntrl);
+ sat_cntrl->state = SAT_FATAL_DETECT;
+ spin_unlock_irqrestore(&sat_cntrl->state_lock, flags);
}
static void mhi_sat_dev_remove(struct mhi_device *mhi_dev)
@@ -822,9 +949,7 @@ static void mhi_sat_dev_remove(struct mhi_device *mhi_dev)
struct mhi_sat_cntrl *sat_cntrl = sat_dev->cntrl;
struct mhi_sat_subsys *subsys = sat_cntrl->subsys;
struct mhi_buf *buf, *tmp;
- struct sat_tre *pkt;
- void *msg;
- int ret;
+ bool send_sys_err = false;
/* remove device node from probed list */
mutex_lock(&sat_cntrl->list_mutex);
@@ -834,45 +959,19 @@ static void mhi_sat_dev_remove(struct mhi_device *mhi_dev)
sat_cntrl->num_devices--;
mutex_lock(&subsys->cntrl_mutex);
- /* prepare SYS_ERR command if first device is being removed */
- if (sat_cntrl->active) {
- sat_cntrl->active = false;
- /* flush all pending work */
- flush_work(&sat_cntrl->connect_work);
- flush_work(&sat_cntrl->process_work);
+ async_synchronize_cookie(sat_cntrl->error_cookie + 1);
- msg = kmalloc(SAT_MSG_SIZE(1), GFP_KERNEL);
+ /* send sys_err if first device is removed */
+ spin_lock_irq(&sat_cntrl->state_lock);
+ if (MHI_SAT_ACTIVE(sat_cntrl) || MHI_SAT_FATAL_DETECT(sat_cntrl))
+ send_sys_err = true;
+ sat_cntrl->state = SAT_ERROR;
+ spin_unlock_irq(&sat_cntrl->state_lock);
- MHI_SAT_ASSERT(!msg, "Unable to malloc for SYS_ERR message!\n");
+ if (send_sys_err)
+ mhi_sat_send_sys_err(sat_cntrl);
- pkt = SAT_TRE_OFFSET(msg);
- pkt->ptr = MHI_TRE_CMD_SYS_ERR_PTR;
- pkt->dword[0] = MHI_TRE_CMD_SYS_ERR_D0;
- pkt->dword[1] = MHI_TRE_CMD_SYS_ERR_D1;
-
- /* acquire cmd_wait_mutex before sending command */
- mutex_lock(&sat_cntrl->cmd_wait_mutex);
-
- ret = mhi_sat_send_msg(sat_cntrl, SAT_MSG_ID_CMD,
- SAT_RESERVED_SEQ_NUM, msg,
- SAT_MSG_SIZE(1));
- kfree(msg);
- if (ret) {
- MHI_SAT_ERR("Failed to notify SYS_ERR\n");
- mutex_unlock(&sat_cntrl->cmd_wait_mutex);
- goto exit_sys_err_send;
- }
-
- MHI_SAT_LOG("SYS_ERR command sent\n");
-
- /* blocking call to wait for command completion event */
- mhi_sat_wait_cmd_completion(sat_cntrl);
-
- mutex_unlock(&sat_cntrl->cmd_wait_mutex);
- }
-
-exit_sys_err_send:
/* exit if some devices are still present */
if (sat_cntrl->num_devices) {
mutex_unlock(&subsys->cntrl_mutex);
@@ -937,6 +1036,7 @@ static int mhi_sat_dev_probe(struct mhi_device *mhi_dev,
mutex_init(&sat_cntrl->list_mutex);
mutex_init(&sat_cntrl->cmd_wait_mutex);
spin_lock_init(&sat_cntrl->pkt_lock);
+ spin_lock_init(&sat_cntrl->state_lock);
INIT_WORK(&sat_cntrl->connect_work, mhi_sat_connect_worker);
INIT_WORK(&sat_cntrl->process_work, mhi_sat_process_worker);
INIT_LIST_HEAD(&sat_cntrl->dev_list);
@@ -1006,17 +1106,6 @@ static const struct mhi_device_id mhi_sat_dev_match_table[] = {
{ .chan = "ADSP_7", .driver_data = SUBSYS_ADSP },
{ .chan = "ADSP_8", .driver_data = SUBSYS_ADSP },
{ .chan = "ADSP_9", .driver_data = SUBSYS_ADSP },
- /* CDSP */
- { .chan = "CDSP_0", .driver_data = SUBSYS_CDSP },
- { .chan = "CDSP_1", .driver_data = SUBSYS_CDSP },
- { .chan = "CDSP_2", .driver_data = SUBSYS_CDSP },
- { .chan = "CDSP_3", .driver_data = SUBSYS_CDSP },
- { .chan = "CDSP_4", .driver_data = SUBSYS_CDSP },
- { .chan = "CDSP_5", .driver_data = SUBSYS_CDSP },
- { .chan = "CDSP_6", .driver_data = SUBSYS_CDSP },
- { .chan = "CDSP_7", .driver_data = SUBSYS_CDSP },
- { .chan = "CDSP_8", .driver_data = SUBSYS_CDSP },
- { .chan = "CDSP_9", .driver_data = SUBSYS_CDSP },
/* SLPI */
{ .chan = "SLPI_0", .driver_data = SUBSYS_SLPI },
{ .chan = "SLPI_1", .driver_data = SUBSYS_SLPI },
@@ -1028,17 +1117,6 @@ static const struct mhi_device_id mhi_sat_dev_match_table[] = {
{ .chan = "SLPI_7", .driver_data = SUBSYS_SLPI },
{ .chan = "SLPI_8", .driver_data = SUBSYS_SLPI },
{ .chan = "SLPI_9", .driver_data = SUBSYS_SLPI },
- /* MODEM */
- { .chan = "MODEM_0", .driver_data = SUBSYS_MODEM },
- { .chan = "MODEM_1", .driver_data = SUBSYS_MODEM },
- { .chan = "MODEM_2", .driver_data = SUBSYS_MODEM },
- { .chan = "MODEM_3", .driver_data = SUBSYS_MODEM },
- { .chan = "MODEM_4", .driver_data = SUBSYS_MODEM },
- { .chan = "MODEM_5", .driver_data = SUBSYS_MODEM },
- { .chan = "MODEM_6", .driver_data = SUBSYS_MODEM },
- { .chan = "MODEM_7", .driver_data = SUBSYS_MODEM },
- { .chan = "MODEM_8", .driver_data = SUBSYS_MODEM },
- { .chan = "MODEM_9", .driver_data = SUBSYS_MODEM },
{},
};
@@ -1053,44 +1131,6 @@ static struct mhi_driver mhi_sat_dev_driver = {
},
};
-int mhi_sat_trigger_init(void *data, u64 val)
-{
- struct mhi_sat_subsys *subsys;
- int i, ret;
-
- if (mhi_sat_driver.deferred_init_done)
- return -EIO;
-
- ret = register_rpmsg_driver(&mhi_sat_rpmsg_driver);
- if (ret)
- goto error_sat_trigger_init;
-
- ret = mhi_driver_register(&mhi_sat_dev_driver);
- if (ret)
- goto error_sat_trigger_register;
-
- mhi_sat_driver.deferred_init_done = true;
-
- return 0;
-
-error_sat_trigger_register:
- unregister_rpmsg_driver(&mhi_sat_rpmsg_driver);
-
-error_sat_trigger_init:
- subsys = mhi_sat_driver.subsys;
- for (i = 0; i < mhi_sat_driver.num_subsys; i++, subsys++) {
- ipc_log_context_destroy(subsys->ipc_log);
- mutex_destroy(&subsys->cntrl_mutex);
- }
- kfree(mhi_sat_driver.subsys);
- mhi_sat_driver.subsys = NULL;
-
- return ret;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(mhi_sat_debugfs_fops, NULL,
- mhi_sat_trigger_init, "%llu\n");
-
static int mhi_sat_init(void)
{
struct mhi_sat_subsys *subsys;
@@ -1116,20 +1156,6 @@ static int mhi_sat_init(void)
subsys->ipc_log = ipc_log_context_create(IPC_LOG_PAGES, log, 0);
}
- /* create debugfs entry if defer_init is enabled */
- if (mhi_sat_defer_init) {
- mhi_sat_driver.dentry = debugfs_create_dir("mhi_sat", NULL);
- if (IS_ERR_OR_NULL(mhi_sat_driver.dentry)) {
- ret = -ENODEV;
- goto error_sat_init;
- }
-
- debugfs_create_file("debug", 0444, mhi_sat_driver.dentry, NULL,
- &mhi_sat_debugfs_fops);
-
- return 0;
- }
-
ret = register_rpmsg_driver(&mhi_sat_rpmsg_driver);
if (ret)
goto error_sat_init;
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 2819868..f8c47e9 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -551,13 +551,21 @@
subsystems crash.
config MSM_ADSPRPC
- tristate "QTI ADSP RPC driver"
- depends on QCOM_GLINK
- help
- Provides a communication mechanism that allows clients to
- make remote method invocations across processor boundary to
- applications/compute DSP processor.
- Say M if you want to enable this module.
+ tristate "QTI FastRPC driver"
+ depends on QCOM_GLINK
+ help
+ Provides a communication mechanism that allows clients to
+ make remote method invocations across processor boundary to
+ applications/compute DSP processor.
+ Say M if you want to enable this module.
+
+config ADSPRPC_DEBUG
+ bool "Debug logs in FastRPC driver"
+ help
+ Enable debug logs in the fastrpc driver. Flag will be
+ disabled by default to maximize RPC performance as debug
+ logging will impact RPC overhead.
+ Say Y here if you want to enable the logs.
config MSM_RDBG
tristate "QTI Remote debug driver"
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index a457a86..bb33190 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -17,6 +17,7 @@
#include <linux/msm_ion.h>
#include <soc/qcom/secure_buffer.h>
#include <linux/rpmsg.h>
+#include <linux/ipc_logging.h>
#include <soc/qcom/subsystem_notif.h>
#include <soc/qcom/subsystem_restart.h>
#include <soc/qcom/service-notifier.h>
@@ -129,6 +130,15 @@
(int64_t *)(perf_ptr + offset)\
: (int64_t *)NULL) : (int64_t *)NULL)
+#define FASTRPC_GLINK_LOG_PAGES 8
+#define LOG_FASTRPC_GLINK_MSG(ctx, x, ...) \
+ do { \
+ if (ctx) \
+ ipc_log_string(ctx, "%s (%d, %d): "x, \
+ current->comm, current->tgid, current->pid, \
+ ##__VA_ARGS__); \
+ } while (0)
+
static int fastrpc_pdr_notifier_cb(struct notifier_block *nb,
unsigned long code,
void *data);
@@ -295,6 +305,7 @@ struct fastrpc_channel_ctx {
/* Indicates, if channel is restricted to secure node only */
int secure;
struct fastrpc_dsp_capabilities dsp_cap_kernel;
+ void *ipc_log_ctx;
};
struct fastrpc_apps {
@@ -796,7 +807,7 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd,
struct fastrpc_session_ctx *sess;
struct fastrpc_apps *apps = fl->apps;
int cid = fl->cid;
- struct fastrpc_channel_ctx *chan = &apps->channel[cid];
+ struct fastrpc_channel_ctx *chan = NULL;
struct fastrpc_mmap *map = NULL;
dma_addr_t region_phys = 0;
void *region_vaddr = NULL;
@@ -804,6 +815,11 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd,
int err = 0, vmid, sgl_index = 0;
struct scatterlist *sgl = NULL;
+ VERIFY(err, cid >= 0 && cid < NUM_CHANNELS);
+ if (err)
+ goto bail;
+ chan = &apps->channel[cid];
+
if (!fastrpc_mmap_find(fl, fd, va, len, mflags, 1, ppmap))
return 0;
map = kzalloc(sizeof(*map), GFP_KERNEL);
@@ -1853,6 +1869,10 @@ static int fastrpc_invoke_send(struct smq_invoke_ctx *ctx,
goto bail;
}
err = rpmsg_send(channel_ctx->rpdev->ept, (void *)msg, sizeof(*msg));
+ LOG_FASTRPC_GLINK_MSG(channel_ctx->ipc_log_ctx,
+ "sent pkt %pK (sz %d): ctx 0x%llx, handle 0x%x, sc 0x%x (rpmsg err %d)",
+ (void *)msg, sizeof(*msg),
+ msg->invoke.header.ctx, handle, ctx->sc, err);
mutex_unlock(&channel_ctx->rpmsg_mutex);
bail:
return err;
@@ -2945,10 +2965,9 @@ static int fastrpc_session_alloc_locked(struct fastrpc_channel_ctx *chan,
return err;
}
-static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
+static inline int get_cid_from_rpdev(struct rpmsg_device *rpdev)
{
- int err = 0;
- int cid = -1;
+ int err = 0, cid = -1;
VERIFY(err, !IS_ERR_OR_NULL(rpdev));
if (err)
@@ -2963,6 +2982,19 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
else if (!strcmp(rpdev->dev.parent->of_node->name, "mdsp"))
cid = MDSP_DOMAIN_ID;
+ return cid;
+}
+
+static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
+{
+ int err = 0;
+ int cid = -1;
+
+ VERIFY(err, !IS_ERR_OR_NULL(rpdev));
+ if (err)
+ return -EINVAL;
+
+ cid = get_cid_from_rpdev(rpdev);
VERIFY(err, cid >= 0 && cid < NUM_CHANNELS);
if (err)
goto bail;
@@ -2971,6 +3003,19 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
mutex_unlock(&gcinfo[cid].rpmsg_mutex);
pr_info("adsprpc: %s: opened rpmsg channel for %s\n",
__func__, gcinfo[cid].subsys);
+
+#if IS_ENABLED(CONFIG_ADSPRPC_DEBUG)
+ if (!gcinfo[cid].ipc_log_ctx)
+ gcinfo[cid].ipc_log_ctx =
+ ipc_log_context_create(FASTRPC_GLINK_LOG_PAGES,
+ gcinfo[cid].name, 0);
+ if (!gcinfo[cid].ipc_log_ctx)
+ pr_warn("adsprpc: %s: failed to create IPC log context for %s\n",
+ __func__, gcinfo[cid].subsys);
+ else
+ pr_info("adsprpc: %s: enabled IPC logging for %s\n",
+ __func__, gcinfo[cid].subsys);
+#endif
bail:
if (err)
pr_err("adsprpc: rpmsg probe of %s cid %d failed\n",
@@ -2988,15 +3033,7 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
if (err)
return;
- if (!strcmp(rpdev->dev.parent->of_node->name, "cdsp"))
- cid = CDSP_DOMAIN_ID;
- else if (!strcmp(rpdev->dev.parent->of_node->name, "adsp"))
- cid = ADSP_DOMAIN_ID;
- else if (!strcmp(rpdev->dev.parent->of_node->name, "dsps"))
- cid = SDSP_DOMAIN_ID;
- else if (!strcmp(rpdev->dev.parent->of_node->name, "mdsp"))
- cid = MDSP_DOMAIN_ID;
-
+ cid = get_cid_from_rpdev(rpdev);
VERIFY(err, cid >= 0 && cid < NUM_CHANNELS);
if (err)
goto bail;
@@ -3024,6 +3061,17 @@ static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
if (err)
goto bail;
+#if IS_ENABLED(CONFIG_ADSPRPC_DEBUG)
+ int cid = -1;
+
+ cid = get_cid_from_rpdev(rpdev);
+ if (cid >= 0 && cid < NUM_CHANNELS) {
+ LOG_FASTRPC_GLINK_MSG(gcinfo[cid].ipc_log_ctx,
+ "recvd pkt %pK (sz %d): ctx 0x%llx, retVal %d",
+ data, len, rsp->ctx, rsp->retval);
+ }
+#endif
+
index = (uint32_t)((rsp->ctx & FASTRPC_CTXID_MASK) >> 4);
VERIFY(err, index < FASTRPC_CTX_MAX);
if (err)
@@ -3041,7 +3089,8 @@ static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
context_notify_user(me->ctxtable[index], rsp->retval);
bail:
if (err)
- pr_err("adsprpc: invalid response or context (err %d)\n", err);
+ pr_err("adsprpc: ERROR: %s: invalid response (data %pK, len %d) from remote subsystem (err %d)\n",
+ __func__, data, len, err);
return err;
}
@@ -4500,6 +4549,8 @@ static void __exit fastrpc_device_exit(void)
for (i = 0; i < NUM_CHANNELS; i++) {
if (!gcinfo[i].name)
continue;
+ if (me->channel[i].ipc_log_ctx)
+ ipc_log_context_destroy(me->channel[i].ipc_log_ctx);
subsys_notif_unregister_notifier(me->channel[i].handle,
&me->channel[i].nb);
}
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 5ba540c..2ae87eb 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -2091,6 +2091,11 @@ static int diag_process_dci_pkt_rsp(unsigned char *buf, int len)
if ((ret == DIAG_DCI_NO_ERROR && !common_cmd) || ret < 0)
return ret;
+ reg_entry.cmd_code = 0;
+ reg_entry.subsys_id = 0;
+ reg_entry.cmd_code_hi = 0;
+ reg_entry.cmd_code_lo = 0;
+
if (header_len >= (sizeof(uint8_t)))
reg_entry.cmd_code = header->cmd_code;
if (header_len >= (2 * sizeof(uint8_t)))
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
index df6b72b..fd40fce 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -440,8 +440,7 @@ static ssize_t diag_dbgfs_read_usbinfo(struct file *file, char __user *ubuf,
"write count: %lu\n"
"read work pending: %d\n"
"read done work pending: %d\n"
- "connect work pending: %d\n"
- "disconnect work pending: %d\n"
+ "event work pending: %d\n"
"max size supported: %d\n\n",
usb_info->id,
usb_info->name,
@@ -455,8 +454,7 @@ static ssize_t diag_dbgfs_read_usbinfo(struct file *file, char __user *ubuf,
usb_info->write_cnt,
work_pending(&usb_info->read_work),
work_pending(&usb_info->read_done_work),
- work_pending(&usb_info->connect_work),
- work_pending(&usb_info->disconnect_work),
+ work_pending(&usb_info->event_work),
usb_info->max_size);
bytes_in_buffer += bytes_written;
diff --git a/drivers/char/diag/diag_usb.c b/drivers/char/diag/diag_usb.c
index 547ced8..682c7a6 100644
--- a/drivers/char/diag/diag_usb.c
+++ b/drivers/char/diag/diag_usb.c
@@ -86,7 +86,29 @@ struct diag_usb_info diag_usb[NUM_DIAG_USB_DEV] = {
}
#endif
};
+static int diag_usb_event_add(struct diag_usb_info *usb_info, int data)
+{
+ struct diag_usb_event_q *entry = NULL;
+ entry = kzalloc(sizeof(struct diag_usb_event_q), GFP_ATOMIC);
+ if (!entry)
+ return -ENOMEM;
+
+ entry->data = data;
+ INIT_LIST_HEAD(&entry->link);
+ list_add_tail(&entry->link, &usb_info->event_q);
+
+ return 0;
+}
+static void diag_usb_event_remove(struct diag_usb_event_q *entry)
+{
+ if (!entry)
+ return;
+
+ list_del(&entry->link);
+ kfree(entry);
+ entry = NULL;
+}
static int diag_usb_buf_tbl_add(struct diag_usb_info *usb_info,
unsigned char *buf, uint32_t len, int ctxt)
{
@@ -194,25 +216,6 @@ static void usb_connect(struct diag_usb_info *ch)
queue_work(ch->usb_wq, &(ch->read_work));
}
-static void usb_connect_work_fn(struct work_struct *work)
-{
- struct diag_usb_info *ch = container_of(work, struct diag_usb_info,
- connect_work);
-
- wait_event_interruptible(ch->wait_q, ch->enabled > 0);
- ch->max_size = usb_diag_request_size(ch->hdl);
- atomic_set(&ch->connected, 1);
-
- DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
- "diag: USB channel %s: disconnected_status: %d, connected_status: %d\n",
- ch->name, atomic_read(&ch->disconnected), atomic_read(&ch->connected));
-
- usb_connect(ch);
-
- if (atomic_read(&ch->disconnected))
- wake_up_interruptible(&ch->wait_q);
-}
-
/*
* This function is called asynchronously when USB is disconnected
* and synchronously when Diag wants to disconnect from USB
@@ -224,32 +227,48 @@ static void usb_disconnect(struct diag_usb_info *ch)
ch->ops->close(ch->ctxt, DIAG_USB_MODE);
}
-static void usb_disconnect_work_fn(struct work_struct *work)
+static void usb_event_work_fn(struct work_struct *work)
{
struct diag_usb_info *ch = container_of(work, struct diag_usb_info,
- disconnect_work);
+ event_work);
+ struct diag_usb_event_q *entry = NULL;
if (!ch)
return;
+ entry = list_first_entry(&(ch->event_q), struct diag_usb_event_q, link);
+ if (!entry)
+ return;
- atomic_set(&ch->disconnected, 1);
- DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
- "diag: USB channel %s: disconnected_status: %d, connected_status: %d\n",
- ch->name, atomic_read(&ch->disconnected), atomic_read(&ch->connected));
+ switch (entry->data) {
+ case USB_DIAG_CONNECT:
+ wait_event_interruptible(ch->wait_q, ch->enabled > 0);
+ ch->max_size = usb_diag_request_size(ch->hdl);
+ atomic_set(&ch->connected, 1);
- wait_event_interruptible(ch->wait_q, atomic_read(&ch->connected) > 0);
- atomic_set(&ch->connected, 0);
- atomic_set(&ch->disconnected, 0);
- DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
- "diag: USB channel %s: Cleared disconnected(%d) and connected(%d) status\n",
- ch->name, atomic_read(&ch->disconnected), atomic_read(&ch->connected));
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: USB channel %s: connected_status: %d\n",
+ ch->name, atomic_read(&ch->connected));
- if (!atomic_read(&ch->connected) &&
- driver->usb_connected && diag_mask_param() &&
- ch->id == DIAG_USB_LOCAL)
- diag_clear_masks(0);
+ usb_connect(ch);
+ break;
+ case USB_DIAG_DISCONNECT:
+ atomic_set(&ch->connected, 0);
+ DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
+ "diag: USB channel %s: Cleared connected(%d) status\n",
+ ch->name, atomic_read(&ch->connected));
- usb_disconnect(ch);
+ if (!atomic_read(&ch->connected) &&
+ driver->usb_connected &&
+ (ch->id == DIAG_USB_LOCAL) && diag_mask_param())
+ diag_clear_masks(0);
+
+ usb_disconnect(ch);
+ break;
+ }
+ diag_usb_event_remove(entry);
+ if (!list_empty(&ch->event_q))
+ queue_work(ch->usb_wq, &(ch->event_work));
+
}
static void usb_read_work_fn(struct work_struct *work)
@@ -378,15 +397,16 @@ static void diag_usb_notifier(void *priv, unsigned int event,
case USB_DIAG_CONNECT:
pr_info("diag: USB channel %s: Received Connect event\n",
usb_info->name);
- if (!atomic_read(&usb_info->connected))
- queue_work(usb_info->usb_wq,
- &usb_info->connect_work);
+ diag_usb_event_add(usb_info, USB_DIAG_CONNECT);
+ queue_work(usb_info->usb_wq,
+ &usb_info->event_work);
break;
case USB_DIAG_DISCONNECT:
pr_info("diag: USB channel %s: Received Disconnect event\n",
usb_info->name);
+ diag_usb_event_add(usb_info, USB_DIAG_DISCONNECT);
queue_work(usb_info->usb_wq,
- &usb_info->disconnect_work);
+ &usb_info->event_work);
break;
case USB_DIAG_READ_DONE:
spin_lock_irqsave(&usb_info->lock, flags);
@@ -665,7 +685,6 @@ int diag_usb_register(int id, int ctxt, struct diag_mux_ops *ops)
if (!ch->read_ptr)
goto err;
atomic_set(&ch->connected, 0);
- atomic_set(&ch->disconnected, 0);
atomic_set(&ch->read_pending, 0);
/*
* This function is called when the mux registers with Diag-USB.
@@ -674,11 +693,11 @@ int diag_usb_register(int id, int ctxt, struct diag_mux_ops *ops)
*/
atomic_set(&ch->diag_state, 1);
INIT_LIST_HEAD(&ch->buf_tbl);
+ INIT_LIST_HEAD(&ch->event_q);
diagmem_init(driver, ch->mempool);
INIT_WORK(&(ch->read_work), usb_read_work_fn);
INIT_WORK(&(ch->read_done_work), usb_read_done_work_fn);
- INIT_WORK(&(ch->connect_work), usb_connect_work_fn);
- INIT_WORK(&(ch->disconnect_work), usb_disconnect_work_fn);
+ INIT_WORK(&(ch->event_work), usb_event_work_fn);
init_waitqueue_head(&ch->wait_q);
strlcpy(wq_name, "DIAG_USB_", sizeof(wq_name));
strlcat(wq_name, ch->name, sizeof(wq_name));
diff --git a/drivers/char/diag/diag_usb.h b/drivers/char/diag/diag_usb.h
index c91735c..35242bb 100644
--- a/drivers/char/diag/diag_usb.h
+++ b/drivers/char/diag/diag_usb.h
@@ -38,6 +38,11 @@ struct diag_usb_buf_tbl_t {
int ctxt;
};
+struct diag_usb_event_q {
+ struct list_head link;
+ int data;
+};
+
struct diag_usb_info {
int id;
int ctxt;
@@ -45,7 +50,6 @@ struct diag_usb_info {
atomic_t connected;
atomic_t diag_state;
atomic_t read_pending;
- atomic_t disconnected;
int enabled;
int mempool;
int max_size;
@@ -60,10 +64,10 @@ struct diag_usb_info {
struct diag_request *read_ptr;
struct work_struct read_work;
struct work_struct read_done_work;
- struct work_struct connect_work;
- struct work_struct disconnect_work;
+ struct work_struct event_work;
struct workqueue_struct *usb_wq;
wait_queue_head_t wait_q;
+ struct list_head event_q;
};
#ifdef CONFIG_DIAG_OVER_USB
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 9bffcd3..c0732f0 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -570,8 +570,7 @@ static inline unsigned long hpet_time_div(struct hpets *hpets,
unsigned long long m;
m = hpets->hp_tick_freq + (dis >> 1);
- do_div(m, dis);
- return (unsigned long)m;
+ return div64_ul(m, dis);
}
static int
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index a72c058..89fa68b 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -407,3 +407,12 @@
Support for the debug clock controller on Qualcomm Technologies, Inc
LITO devices.
Say Y if you want to support the clock measurement functionality.
+
+config SM_GCC_BENGAL
+ tristate "BENGAL Global Clock Controller"
+ select QCOM_GDSC
+ depends on COMMON_CLK_QCOM
+ help
+ Support for the global clock controller on Bengal devices.
+ Say Y if you want to use peripheral devices such as UART, SPI,
+ I2C, USB, UFS, SDCC, PCIe, Camera, Video etc.
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 40dca85..d70dbc3 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -55,6 +55,7 @@
obj-$(CONFIG_SM_CAMCC_LITO) += camcc-lito.o
obj-$(CONFIG_SM_DEBUGCC_LITO) += debugcc-lito.o
obj-$(CONFIG_SM_DISPCC_LITO) += dispcc-lito.o
+obj-$(CONFIG_SM_GCC_BENGAL) += gcc-bengal.o
obj-$(CONFIG_SM_GCC_LITO) += gcc-lito.o
obj-$(CONFIG_SM_NPUCC_LITO) += npucc-lito.o
obj-$(CONFIG_SM_VIDEOCC_LITO) += videocc-lito.o
diff --git a/drivers/clk/qcom/camcc-kona.c b/drivers/clk/qcom/camcc-kona.c
index 95637b2..f15be8e 100644
--- a/drivers/clk/qcom/camcc-kona.c
+++ b/drivers/clk/qcom/camcc-kona.c
@@ -328,7 +328,6 @@ static const struct alpha_pll_config cam_cc_pll2_config_sm8250_v2 = {
.config_ctl_val = 0x08200920,
.config_ctl_hi_val = 0x05008011,
.config_ctl_hi1_val = 0x00000000,
- .test_ctl_val = 0x00010000,
.user_ctl_val = 0x00000100,
.user_ctl_hi_val = 0x00000000,
.user_ctl_hi1_val = 0x00000000,
diff --git a/drivers/clk/qcom/gcc-bengal.c b/drivers/clk/qcom/gcc-bengal.c
new file mode 100644
index 0000000..b2cad01
--- /dev/null
+++ b/drivers/clk/qcom/gcc-bengal.c
@@ -0,0 +1,3897 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ */
+
+#define pr_fmt(fmt) "clk: %s: " fmt, __func__
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+
+#include <dt-bindings/clock/qcom,gcc-bengal.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "common.h"
+#include "reset.h"
+#include "vdd-level-bengal.h"
+
+static DEFINE_VDD_REGULATORS(vdd_cx, VDD_NUM, 1, vdd_corner);
+static DEFINE_VDD_REGULATORS(vdd_cx_ao, VDD_NUM, 1, vdd_corner);
+static DEFINE_VDD_REGULATORS(vdd_mx, VDD_NUM, 1, vdd_corner);
+
+enum {
+ P_BI_TCXO,
+ P_CORE_BI_PLL_TEST_SE,
+ P_GPLL0_OUT_AUX2,
+ P_GPLL0_OUT_EARLY,
+ P_GPLL10_OUT_MAIN,
+ P_GPLL11_OUT_AUX,
+ P_GPLL11_OUT_AUX2,
+ P_GPLL11_OUT_MAIN,
+ P_GPLL3_OUT_EARLY,
+ P_GPLL3_OUT_MAIN,
+ P_GPLL4_OUT_MAIN,
+ P_GPLL6_OUT_EARLY,
+ P_GPLL6_OUT_MAIN,
+ P_GPLL7_OUT_MAIN,
+ P_GPLL8_OUT_EARLY,
+ P_GPLL8_OUT_MAIN,
+ P_GPLL9_OUT_EARLY,
+ P_GPLL9_OUT_MAIN,
+ P_SLEEP_CLK,
+};
+
+static const struct parent_map gcc_parent_map_0[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL0_OUT_AUX2, 2 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_0[] = {
+ "bi_tcxo",
+ "gpll0",
+ "gpll0_out_aux2",
+ "core_bi_pll_test_se",
+};
+static const char * const gcc_parent_names_0_ao[] = {
+ "bi_tcxo_ao",
+ "gpll0",
+ "gpll0_out_aux2",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_1[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL0_OUT_AUX2, 2 },
+ { P_GPLL6_OUT_MAIN, 4 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_1[] = {
+ "bi_tcxo",
+ "gpll0",
+ "gpll0_out_aux2",
+ "gpll6_out_main",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_2[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL0_OUT_AUX2, 2 },
+ { P_SLEEP_CLK, 5 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_2[] = {
+ "bi_tcxo",
+ "gpll0",
+ "gpll0_out_aux2",
+ "sleep_clk",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_3[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL9_OUT_EARLY, 2 },
+ { P_GPLL10_OUT_MAIN, 3 },
+ { P_GPLL9_OUT_MAIN, 5 },
+ { P_GPLL3_OUT_MAIN, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_3[] = {
+ "bi_tcxo",
+ "gpll0",
+ "gpll9",
+ "gpll10_out_main",
+ "gpll9_out_main",
+ "gpll3_out_main",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_4[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL0_OUT_AUX2, 2 },
+ { P_GPLL4_OUT_MAIN, 5 },
+ { P_GPLL3_OUT_MAIN, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_4[] = {
+ "bi_tcxo",
+ "gpll0",
+ "gpll0_out_aux2",
+ "gpll4_out_main",
+ "gpll3_out_main",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_5[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL8_OUT_EARLY, 2 },
+ { P_GPLL10_OUT_MAIN, 3 },
+ { P_GPLL8_OUT_MAIN, 4 },
+ { P_GPLL9_OUT_MAIN, 5 },
+ { P_GPLL3_OUT_MAIN, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_5[] = {
+ "bi_tcxo",
+ "gpll0",
+ "gpll8",
+ "gpll10_out_main",
+ "gpll8_out_main",
+ "gpll9_out_main",
+ "gpll3_out_main",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_6[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL8_OUT_EARLY, 2 },
+ { P_GPLL10_OUT_MAIN, 3 },
+ { P_GPLL6_OUT_MAIN, 4 },
+ { P_GPLL9_OUT_MAIN, 5 },
+ { P_GPLL3_OUT_EARLY, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_6[] = {
+ "bi_tcxo",
+ "gpll0",
+ "gpll8",
+ "gpll10_out_main",
+ "gpll6_out_main",
+ "gpll9_out_main",
+ "gpll3",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_7[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL0_OUT_AUX2, 2 },
+ { P_GPLL10_OUT_MAIN, 3 },
+ { P_GPLL4_OUT_MAIN, 5 },
+ { P_GPLL3_OUT_EARLY, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_7[] = {
+ "bi_tcxo",
+ "gpll0",
+ "gpll0_out_aux2",
+ "gpll10_out_main",
+ "gpll4_out_main",
+ "gpll3",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_8[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL8_OUT_EARLY, 2 },
+ { P_GPLL10_OUT_MAIN, 3 },
+ { P_GPLL8_OUT_MAIN, 4 },
+ { P_GPLL9_OUT_MAIN, 5 },
+ { P_GPLL3_OUT_EARLY, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_8[] = {
+ "bi_tcxo",
+ "gpll0",
+ "gpll8",
+ "gpll10_out_main",
+ "gpll8_out_main",
+ "gpll9_out_main",
+ "gpll3",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_9[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL0_OUT_AUX2, 2 },
+ { P_GPLL10_OUT_MAIN, 3 },
+ { P_GPLL8_OUT_MAIN, 4 },
+ { P_GPLL9_OUT_MAIN, 5 },
+ { P_GPLL3_OUT_EARLY, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_9[] = {
+ "bi_tcxo",
+ "gpll0",
+ "gpll0_out_aux2",
+ "gpll10_out_main",
+ "gpll8_out_main",
+ "gpll9_out_main",
+ "gpll3",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_10[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL8_OUT_EARLY, 2 },
+ { P_GPLL10_OUT_MAIN, 3 },
+ { P_GPLL6_OUT_EARLY, 4 },
+ { P_GPLL9_OUT_MAIN, 5 },
+ { P_GPLL3_OUT_MAIN, 6 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_10[] = {
+ "bi_tcxo",
+ "gpll0",
+ "gpll8",
+ "gpll10_out_main",
+ "gpll6",
+ "gpll9_out_main",
+ "gpll3_out_main",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_11[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL0_OUT_AUX2, 2 },
+ { P_GPLL7_OUT_MAIN, 3 },
+ { P_GPLL4_OUT_MAIN, 5 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_11[] = {
+ "bi_tcxo",
+ "gpll0",
+ "gpll0_out_aux2",
+ "gpll7_out_main",
+ "gpll4_out_main",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_12[] = {
+ { P_BI_TCXO, 0 },
+ { P_SLEEP_CLK, 5 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_12[] = {
+ "bi_tcxo",
+ "sleep_clk",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_13[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL11_OUT_MAIN, 1 },
+ { P_GPLL11_OUT_AUX, 2 },
+ { P_GPLL11_OUT_AUX2, 3 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_13[] = {
+ "bi_tcxo",
+ "gpll11_out_main",
+ "gpll11_out_aux",
+ "gpll11_out_aux2",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_14[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_14[] = {
+ "bi_tcxo",
+ "gpll0",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gcc_parent_map_15[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_EARLY, 1 },
+ { P_GPLL6_OUT_MAIN, 4 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gcc_parent_names_15[] = {
+ "bi_tcxo",
+ "gpll0",
+ "gpll6_out_main",
+ "core_bi_pll_test_se",
+};
+
+static struct pll_vco brammo_vco[] = {
+ { 500000000, 1250000000, 0 },
+};
+
+static struct pll_vco default_vco[] = {
+ { 1000000000, 2000000000, 0 },
+ { 750000000, 1500000000, 1 },
+ { 500000000, 1000000000, 2 },
+ { 250000000, 500000000, 3 },
+};
+
+static const u8 clk_alpha_pll_regs_offset[][PLL_OFF_MAX_REGS] = {
+ [CLK_ALPHA_PLL_TYPE_DEFAULT] = {
+ [PLL_OFF_L_VAL] = 0x04,
+ [PLL_OFF_ALPHA_VAL] = 0x08,
+ [PLL_OFF_ALPHA_VAL_U] = 0x0c,
+ [PLL_OFF_TEST_CTL] = 0x10,
+ [PLL_OFF_TEST_CTL_U] = 0x14,
+ [PLL_OFF_USER_CTL] = 0x18,
+ [PLL_OFF_USER_CTL_U] = 0x1C,
+ [PLL_OFF_CONFIG_CTL] = 0x20,
+ [PLL_OFF_STATUS] = 0x24,
+ },
+ [CLK_ALPHA_PLL_TYPE_BRAMMO] = {
+ [PLL_OFF_L_VAL] = 0x04,
+ [PLL_OFF_ALPHA_VAL] = 0x08,
+ [PLL_OFF_ALPHA_VAL_U] = 0x0c,
+ [PLL_OFF_TEST_CTL] = 0x10,
+ [PLL_OFF_TEST_CTL_U] = 0x14,
+ [PLL_OFF_USER_CTL] = 0x18,
+ [PLL_OFF_CONFIG_CTL] = 0x1C,
+ [PLL_OFF_STATUS] = 0x20,
+ },
+};
+
+static struct clk_alpha_pll gpll0 = {
+ .offset = 0x0,
+ .vco_table = default_vco,
+ .num_vco = ARRAY_SIZE(default_vco),
+ .regs = clk_alpha_pll_regs_offset[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll0",
+ .parent_names = (const char *[]){ "bi_tcxo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_MIN] = 1000000000,
+ [VDD_NOMINAL] = 2000000000},
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_gpll0_out_aux2[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv gpll0_out_aux2 = {
+ .offset = 0x0,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_gpll0_out_aux2,
+ .num_post_div = ARRAY_SIZE(post_div_table_gpll0_out_aux2),
+ .width = 4,
+ .regs = clk_alpha_pll_regs_offset[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gpll0_out_aux2",
+ .parent_names = (const char *[]){ "gpll0" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_ro_ops,
+ },
+};
+
+static const struct clk_div_table post_div_table_gpll0_out_main[] = {
+ { 0x0, 1 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv gpll0_out_main = {
+ .offset = 0x0,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_gpll0_out_main,
+ .num_post_div = ARRAY_SIZE(post_div_table_gpll0_out_main),
+ .width = 4,
+ .regs = clk_alpha_pll_regs_offset[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gpll0_out_main",
+ .parent_names = (const char *[]){ "gpll0" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_ro_ops,
+ },
+};
+
+/* 1152MHz configuration */
+static const struct alpha_pll_config gpll10_config = {
+ .l = 0x3c,
+ .vco_val = 0x1 << 20,
+ .vco_mask = GENMASK(21, 20),
+ .main_output_mask = BIT(0),
+ .config_ctl_val = 0x40008529,
+};
+
+static struct clk_alpha_pll gpll10 = {
+ .offset = 0xa000,
+ .vco_table = default_vco,
+ .num_vco = ARRAY_SIZE(default_vco),
+ .regs = clk_alpha_pll_regs_offset[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(10),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll10",
+ .parent_names = (const char *[]){ "bi_tcxo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ .vdd_class = &vdd_mx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_MIN] = 1000000000,
+ [VDD_NOMINAL] = 2000000000},
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_gpll10_out_main[] = {
+ { 0x0, 1 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv gpll10_out_main = {
+ .offset = 0xa000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_gpll10_out_main,
+ .num_post_div = ARRAY_SIZE(post_div_table_gpll10_out_main),
+ .width = 4,
+ .regs = clk_alpha_pll_regs_offset[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gpll10_out_main",
+ .parent_names = (const char *[]){ "gpll10" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_ops,
+ },
+};
+
+/* 600MHz configuration */
+static const struct alpha_pll_config gpll11_config = {
+ .l = 0x1F,
+ .alpha = 0x0,
+ .alpha_hi = 0x40,
+ .alpha_en_mask = BIT(24),
+ .vco_val = 0x2 << 20,
+ .vco_mask = GENMASK(21, 20),
+ .config_ctl_val = 0x40008529,
+};
+
+static struct clk_alpha_pll gpll11 = {
+ .offset = 0xb000,
+ .vco_table = default_vco,
+ .num_vco = ARRAY_SIZE(default_vco),
+ .flags = SUPPORTS_DYNAMIC_UPDATE,
+ .regs = clk_alpha_pll_regs_offset[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(11),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll11",
+ .parent_names = (const char *[]){ "bi_tcxo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_MIN] = 1000000000,
+ [VDD_NOMINAL] = 2000000000},
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_gpll11_out_main[] = {
+ { 0x0, 1 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv gpll11_out_main = {
+ .offset = 0xb000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_gpll11_out_main,
+ .num_post_div = ARRAY_SIZE(post_div_table_gpll11_out_main),
+ .width = 4,
+ .regs = clk_alpha_pll_regs_offset[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gpll11_out_main",
+ .parent_names = (const char *[]){ "gpll11" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_ops,
+ },
+};
+
+static struct clk_alpha_pll gpll3 = {
+ .offset = 0x3000,
+ .vco_table = default_vco,
+ .num_vco = ARRAY_SIZE(default_vco),
+ .regs = clk_alpha_pll_regs_offset[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(3),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll3",
+ .parent_names = (const char *[]){ "bi_tcxo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_MIN] = 1000000000,
+ [VDD_NOMINAL] = 2000000000},
+ },
+ },
+};
+
+static struct clk_alpha_pll gpll4 = {
+ .offset = 0x4000,
+ .vco_table = default_vco,
+ .num_vco = ARRAY_SIZE(default_vco),
+ .regs = clk_alpha_pll_regs_offset[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll4",
+ .parent_names = (const char *[]){ "bi_tcxo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_MIN] = 1000000000,
+ [VDD_NOMINAL] = 2000000000},
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_gpll4_out_main[] = {
+ { 0x0, 1 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv gpll4_out_main = {
+ .offset = 0x4000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_gpll4_out_main,
+ .num_post_div = ARRAY_SIZE(post_div_table_gpll4_out_main),
+ .width = 4,
+ .regs = clk_alpha_pll_regs_offset[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gpll4_out_main",
+ .parent_names = (const char *[]){ "gpll4" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_ro_ops,
+ },
+};
+
+static struct clk_alpha_pll gpll6 = {
+ .offset = 0x6000,
+ .vco_table = default_vco,
+ .num_vco = ARRAY_SIZE(default_vco),
+ .regs = clk_alpha_pll_regs_offset[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(6),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll6",
+ .parent_names = (const char *[]){ "bi_tcxo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_MIN] = 1000000000,
+ [VDD_NOMINAL] = 2000000000},
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_gpll6_out_main[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv gpll6_out_main = {
+ .offset = 0x6000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_gpll6_out_main,
+ .num_post_div = ARRAY_SIZE(post_div_table_gpll6_out_main),
+ .width = 4,
+ .regs = clk_alpha_pll_regs_offset[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gpll6_out_main",
+ .parent_names = (const char *[]){ "gpll6" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_ro_ops,
+ },
+};
+
+static struct clk_alpha_pll gpll7 = {
+ .offset = 0x7000,
+ .vco_table = default_vco,
+ .num_vco = ARRAY_SIZE(default_vco),
+ .regs = clk_alpha_pll_regs_offset[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(7),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll7",
+ .parent_names = (const char *[]){ "bi_tcxo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_MIN] = 1000000000,
+ [VDD_NOMINAL] = 2000000000},
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_gpll7_out_main[] = {
+ { 0x0, 1 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv gpll7_out_main = {
+ .offset = 0x7000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_gpll7_out_main,
+ .num_post_div = ARRAY_SIZE(post_div_table_gpll7_out_main),
+ .width = 4,
+ .regs = clk_alpha_pll_regs_offset[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gpll7_out_main",
+ .parent_names = (const char *[]){ "gpll7" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_ro_ops,
+ },
+};
+
+/* 800MHz configuration */
+static const struct alpha_pll_config gpll8_config = {
+ .l = 0x29,
+ .alpha = 0xAA000000,
+ .alpha_hi = 0xAA,
+ .alpha_en_mask = BIT(24),
+ .vco_val = 0x2 << 20,
+ .vco_mask = GENMASK(21, 20),
+ .main_output_mask = BIT(0),
+ .early_output_mask = BIT(3),
+ .post_div_val = 0x1 << 8,
+ .post_div_mask = GENMASK(11, 8),
+ .config_ctl_val = 0x40008529,
+};
+
+static struct clk_alpha_pll gpll8 = {
+ .offset = 0x8000,
+ .vco_table = default_vco,
+ .num_vco = ARRAY_SIZE(default_vco),
+ .regs = clk_alpha_pll_regs_offset[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .flags = SUPPORTS_DYNAMIC_UPDATE,
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(8),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll8",
+ .parent_names = (const char *[]){ "bi_tcxo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_MIN] = 1000000000,
+ [VDD_NOMINAL] = 2000000000},
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_gpll8_out_main[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv gpll8_out_main = {
+ .offset = 0x8000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_gpll8_out_main,
+ .num_post_div = ARRAY_SIZE(post_div_table_gpll8_out_main),
+ .width = 4,
+ .regs = clk_alpha_pll_regs_offset[CLK_ALPHA_PLL_TYPE_DEFAULT],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gpll8_out_main",
+ .parent_names = (const char *[]){ "gpll8" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_ro_ops,
+ },
+};
+
+/* 1152MHz configuration */
+static const struct alpha_pll_config gpll9_config = {
+ .l = 0x3C,
+ .alpha = 0x0,
+ .post_div_val = 0x1 << 8,
+ .post_div_mask = GENMASK(9, 8),
+ .main_output_mask = BIT(0),
+ .config_ctl_val = 0x000040C9,
+};
+
+static struct clk_alpha_pll gpll9 = {
+ .offset = 0x9000,
+ .vco_table = brammo_vco,
+ .num_vco = ARRAY_SIZE(brammo_vco),
+ .regs = clk_alpha_pll_regs_offset[CLK_ALPHA_PLL_TYPE_BRAMMO],
+ .clkr = {
+ .enable_reg = 0x79000,
+ .enable_mask = BIT(9),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpll9",
+ .parent_names = (const char *[]){ "bi_tcxo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_ops,
+ .vdd_class = &vdd_mx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 1250000000,
+ [VDD_LOW] = 1250000000,
+ [VDD_NOMINAL] = 1250000000},
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_gpll9_out_main[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv gpll9_out_main = {
+ .offset = 0x9000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_gpll9_out_main,
+ .num_post_div = ARRAY_SIZE(post_div_table_gpll9_out_main),
+ .width = 2,
+ .regs = clk_alpha_pll_regs_offset[CLK_ALPHA_PLL_TYPE_BRAMMO],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gpll9_out_main",
+ .parent_names = (const char *[]){ "gpll9" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_usb30_prim_mock_utmi_postdiv_clk_src = {
+ .reg = 0x1a04c,
+ .shift = 0,
+ .width = 2,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "gcc_usb30_prim_mock_utmi_postdiv_clk_src",
+ .parent_names =
+ (const char *[]){ "gcc_usb30_prim_mock_utmi_clk_src" },
+ .num_parents = 1,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_axi_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(150000000, P_GPLL0_OUT_AUX2, 2, 0, 0),
+ F(200000000, P_GPLL0_OUT_AUX2, 1.5, 0, 0),
+ F(300000000, P_GPLL0_OUT_AUX2, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_axi_clk_src = {
+ .cmd_rcgr = 0x5802c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_7,
+ .freq_tbl = ftbl_gcc_camss_axi_clk_src,
+ .enable_safe_config = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_axi_clk_src",
+ .parent_names = gcc_parent_names_7,
+ .num_parents = 7,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 19200000,
+ [VDD_LOW] = 150000000,
+ [VDD_LOW_L1] = 200000000,
+ [VDD_NOMINAL] = 300000000},
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_cci_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(37500000, P_GPLL0_OUT_AUX2, 8, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_cci_clk_src = {
+ .cmd_rcgr = 0x56000,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_9,
+ .freq_tbl = ftbl_gcc_camss_cci_clk_src,
+ .enable_safe_config = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_cci_clk_src",
+ .parent_names = gcc_parent_names_9,
+ .num_parents = 8,
+ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 19200000,
+ [VDD_LOW] = 37500000},
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_csi0phytimer_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(100000000, P_GPLL0_OUT_AUX2, 3, 0, 0),
+ F(200000000, P_GPLL0_OUT_AUX2, 1.5, 0, 0),
+ F(268800000, P_GPLL4_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_csi0phytimer_clk_src = {
+ .cmd_rcgr = 0x59000,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_4,
+ .freq_tbl = ftbl_gcc_camss_csi0phytimer_clk_src,
+ .enable_safe_config = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi0phytimer_clk_src",
+ .parent_names = gcc_parent_names_4,
+ .num_parents = 6,
+ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 19200000,
+ [VDD_LOW] = 200000000,
+ [VDD_NOMINAL] = 268800000},
+ },
+};
+
+static struct clk_rcg2 gcc_camss_csi1phytimer_clk_src = {
+ .cmd_rcgr = 0x5901c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_4,
+ .freq_tbl = ftbl_gcc_camss_csi0phytimer_clk_src,
+ .enable_safe_config = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi1phytimer_clk_src",
+ .parent_names = gcc_parent_names_4,
+ .num_parents = 6,
+ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 19200000,
+ [VDD_LOW] = 200000000,
+ [VDD_NOMINAL] = 268800000},
+ },
+};
+
+static struct clk_rcg2 gcc_camss_csi2phytimer_clk_src = {
+ .cmd_rcgr = 0x59038,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_4,
+ .freq_tbl = ftbl_gcc_camss_csi0phytimer_clk_src,
+ .enable_safe_config = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi2phytimer_clk_src",
+ .parent_names = gcc_parent_names_4,
+ .num_parents = 6,
+ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 19200000,
+ [VDD_LOW] = 200000000,
+ [VDD_NOMINAL] = 268800000},
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_mclk0_clk_src[] = {
+ F(24000000, P_GPLL9_OUT_MAIN, 1, 1, 24),
+ F(64000000, P_GPLL9_OUT_MAIN, 1, 1, 9),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_mclk0_clk_src = {
+ .cmd_rcgr = 0x51000,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_camss_mclk0_clk_src,
+ .enable_safe_config = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_mclk0_clk_src",
+ .parent_names = gcc_parent_names_3,
+ .num_parents = 7,
+ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 64000000},
+ },
+};
+
+static struct clk_rcg2 gcc_camss_mclk1_clk_src = {
+ .cmd_rcgr = 0x5101c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_camss_mclk0_clk_src,
+ .enable_safe_config = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_mclk1_clk_src",
+ .parent_names = gcc_parent_names_3,
+ .num_parents = 7,
+ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 64000000},
+ },
+};
+
+static struct clk_rcg2 gcc_camss_mclk2_clk_src = {
+ .cmd_rcgr = 0x51038,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_camss_mclk0_clk_src,
+ .enable_safe_config = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_mclk2_clk_src",
+ .parent_names = gcc_parent_names_3,
+ .num_parents = 7,
+ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 64000000},
+ },
+};
+
+static struct clk_rcg2 gcc_camss_mclk3_clk_src = {
+ .cmd_rcgr = 0x51054,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_camss_mclk0_clk_src,
+ .enable_safe_config = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_mclk3_clk_src",
+ .parent_names = gcc_parent_names_3,
+ .num_parents = 7,
+ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 64000000},
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_ope_ahb_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(171428571, P_GPLL0_OUT_EARLY, 3.5, 0, 0),
+ F(240000000, P_GPLL0_OUT_EARLY, 2.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_ope_ahb_clk_src = {
+ .cmd_rcgr = 0x55024,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_8,
+ .freq_tbl = ftbl_gcc_camss_ope_ahb_clk_src,
+ .enable_safe_config = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_ope_ahb_clk_src",
+ .parent_names = gcc_parent_names_8,
+ .num_parents = 8,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 19200000,
+ [VDD_LOW] = 171428571,
+ [VDD_NOMINAL] = 240000000},
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_ope_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(200000000, P_GPLL8_OUT_MAIN, 2, 0, 0),
+ F(266600000, P_GPLL8_OUT_MAIN, 1, 0, 0),
+ F(465000000, P_GPLL8_OUT_MAIN, 1, 0, 0),
+ F(580000000, P_GPLL8_OUT_EARLY, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_ope_clk_src = {
+ .cmd_rcgr = 0x55004,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_8,
+ .freq_tbl = ftbl_gcc_camss_ope_clk_src,
+ .enable_safe_config = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_ope_clk_src",
+ .parent_names = gcc_parent_names_8,
+ .num_parents = 8,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 19200000,
+ [VDD_LOW] = 200000000,
+ [VDD_LOW_L1] = 266600000,
+ [VDD_NOMINAL] = 465000000,
+ [VDD_HIGH] = 580000000},
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_tfe_0_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(256000000, P_GPLL10_OUT_MAIN, 4.5, 0, 0),
+ F(460800000, P_GPLL10_OUT_MAIN, 2.5, 0, 0),
+ F(576000000, P_GPLL10_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_tfe_0_clk_src = {
+ .cmd_rcgr = 0x52004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_5,
+ .freq_tbl = ftbl_gcc_camss_tfe_0_clk_src,
+ .enable_safe_config = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_tfe_0_clk_src",
+ .parent_names = gcc_parent_names_5,
+ .num_parents = 8,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 19200000,
+ [VDD_LOW] = 256000000,
+ [VDD_LOW_L1] = 460800000,
+ [VDD_NOMINAL] = 576000000},
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_tfe_0_csid_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(240000000, P_GPLL0_OUT_EARLY, 2.5, 0, 0),
+ F(384000000, P_GPLL6_OUT_MAIN, 1, 0, 0),
+ F(426400000, P_GPLL3_OUT_EARLY, 2.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_tfe_0_csid_clk_src = {
+ .cmd_rcgr = 0x52094,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_6,
+ .freq_tbl = ftbl_gcc_camss_tfe_0_csid_clk_src,
+ .enable_safe_config = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_tfe_0_csid_clk_src",
+ .parent_names = gcc_parent_names_6,
+ .num_parents = 8,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 19200000,
+ [VDD_LOW] = 240000000,
+ [VDD_LOW_L1] = 384000000,
+ [VDD_HIGH] = 426400000},
+ },
+};
+
+static struct clk_rcg2 gcc_camss_tfe_1_clk_src = {
+ .cmd_rcgr = 0x52024,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_5,
+ .freq_tbl = ftbl_gcc_camss_tfe_0_clk_src,
+ .enable_safe_config = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_tfe_1_clk_src",
+ .parent_names = gcc_parent_names_5,
+ .num_parents = 8,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 19200000,
+ [VDD_LOW] = 256000000,
+ [VDD_LOW_L1] = 460800000,
+ [VDD_NOMINAL] = 576000000},
+ },
+};
+
+static struct clk_rcg2 gcc_camss_tfe_1_csid_clk_src = {
+ .cmd_rcgr = 0x520b4,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_6,
+ .freq_tbl = ftbl_gcc_camss_tfe_0_csid_clk_src,
+ .enable_safe_config = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_tfe_1_csid_clk_src",
+ .parent_names = gcc_parent_names_6,
+ .num_parents = 8,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 19200000,
+ [VDD_LOW] = 240000000,
+ [VDD_LOW_L1] = 384000000,
+ [VDD_HIGH] = 426400000},
+ },
+};
+
+static struct clk_rcg2 gcc_camss_tfe_2_clk_src = {
+ .cmd_rcgr = 0x52044,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_5,
+ .freq_tbl = ftbl_gcc_camss_tfe_0_clk_src,
+ .enable_safe_config = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_tfe_2_clk_src",
+ .parent_names = gcc_parent_names_5,
+ .num_parents = 8,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 19200000,
+ [VDD_LOW] = 256000000,
+ [VDD_LOW_L1] = 460800000,
+ [VDD_NOMINAL] = 576000000},
+ },
+};
+
+static struct clk_rcg2 gcc_camss_tfe_2_csid_clk_src = {
+ .cmd_rcgr = 0x520d4,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_6,
+ .freq_tbl = ftbl_gcc_camss_tfe_0_csid_clk_src,
+ .enable_safe_config = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_tfe_2_csid_clk_src",
+ .parent_names = gcc_parent_names_6,
+ .num_parents = 8,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 19200000,
+ [VDD_LOW] = 240000000,
+ [VDD_LOW_L1] = 384000000,
+ [VDD_HIGH] = 426400000},
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_tfe_cphy_rx_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(240000000, P_GPLL0_OUT_EARLY, 2.5, 0, 0),
+ F(341333333, P_GPLL6_OUT_EARLY, 1, 4, 9),
+ F(384000000, P_GPLL6_OUT_EARLY, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_tfe_cphy_rx_clk_src = {
+ .cmd_rcgr = 0x52064,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_10,
+ .freq_tbl = ftbl_gcc_camss_tfe_cphy_rx_clk_src,
+ .enable_safe_config = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_tfe_cphy_rx_clk_src",
+ .parent_names = gcc_parent_names_10,
+ .num_parents = 8,
+ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 19200000,
+ [VDD_LOW] = 240000000,
+ [VDD_LOW_L1] = 341333333,
+ [VDD_HIGH] = 384000000},
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_camss_top_ahb_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(40000000, P_GPLL0_OUT_AUX2, 7.5, 0, 0),
+ F(80000000, P_GPLL0_OUT_EARLY, 7.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_camss_top_ahb_clk_src = {
+ .cmd_rcgr = 0x58010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_7,
+ .freq_tbl = ftbl_gcc_camss_top_ahb_clk_src,
+ .enable_safe_config = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_top_ahb_clk_src",
+ .parent_names = gcc_parent_names_7,
+ .num_parents = 7,
+ .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 19200000,
+ [VDD_LOW] = 80000000},
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = {
+ F(25000000, P_GPLL0_OUT_AUX2, 12, 0, 0),
+ F(50000000, P_GPLL0_OUT_AUX2, 6, 0, 0),
+ F(100000000, P_GPLL0_OUT_AUX2, 3, 0, 0),
+ F(200000000, P_GPLL0_OUT_AUX2, 1.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_gp1_clk_src = {
+ .cmd_rcgr = 0x4d004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_gp1_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_gp1_clk_src",
+ .parent_names = gcc_parent_names_2,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 50000000,
+ [VDD_LOW] = 100000000,
+ [VDD_NOMINAL] = 200000000},
+ },
+};
+
+static struct clk_rcg2 gcc_gp2_clk_src = {
+ .cmd_rcgr = 0x4e004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_gp1_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_gp2_clk_src",
+ .parent_names = gcc_parent_names_2,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 50000000,
+ [VDD_LOW] = 100000000,
+ [VDD_NOMINAL] = 200000000},
+ },
+};
+
+static struct clk_rcg2 gcc_gp3_clk_src = {
+ .cmd_rcgr = 0x4f004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_gp1_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_gp3_clk_src",
+ .parent_names = gcc_parent_names_2,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 50000000,
+ [VDD_LOW] = 100000000,
+ [VDD_NOMINAL] = 200000000},
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(60000000, P_GPLL0_OUT_AUX2, 5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_pdm2_clk_src = {
+ .cmd_rcgr = 0x20010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pdm2_clk_src,
+ .enable_safe_config = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_pdm2_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 19200000,
+ [VDD_LOW] = 60000000},
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = {
+ F(7372800, P_GPLL0_OUT_AUX2, 1, 384, 15625),
+ F(14745600, P_GPLL0_OUT_AUX2, 1, 768, 15625),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(29491200, P_GPLL0_OUT_AUX2, 1, 1536, 15625),
+ F(32000000, P_GPLL0_OUT_AUX2, 1, 8, 75),
+ F(48000000, P_GPLL0_OUT_AUX2, 1, 4, 25),
+ F(64000000, P_GPLL0_OUT_AUX2, 1, 16, 75),
+ F(75000000, P_GPLL0_OUT_AUX2, 4, 0, 0),
+ F(80000000, P_GPLL0_OUT_AUX2, 1, 4, 15),
+ F(96000000, P_GPLL0_OUT_AUX2, 1, 8, 25),
+ F(100000000, P_GPLL0_OUT_AUX2, 3, 0, 0),
+ F(102400000, P_GPLL0_OUT_AUX2, 1, 128, 375),
+ F(112000000, P_GPLL0_OUT_AUX2, 1, 28, 75),
+ F(117964800, P_GPLL0_OUT_AUX2, 1, 6144, 15625),
+ F(120000000, P_GPLL0_OUT_AUX2, 2.5, 0, 0),
+ F(128000000, P_GPLL6_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s0_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s0_clk_src",
+ .parent_names = gcc_parent_names_1,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 75000000,
+ [VDD_LOW] = 100000000,
+ [VDD_NOMINAL] = 128000000},
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s0_clk_src = {
+ .cmd_rcgr = 0x1f148,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s0_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s1_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s1_clk_src",
+ .parent_names = gcc_parent_names_1,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 75000000,
+ [VDD_LOW] = 100000000,
+ [VDD_NOMINAL] = 128000000},
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s1_clk_src = {
+ .cmd_rcgr = 0x1f278,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s1_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s2_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s2_clk_src",
+ .parent_names = gcc_parent_names_1,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 75000000,
+ [VDD_LOW] = 100000000,
+ [VDD_NOMINAL] = 128000000},
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s2_clk_src = {
+ .cmd_rcgr = 0x1f3a8,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s2_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s3_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s3_clk_src",
+ .parent_names = gcc_parent_names_1,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 75000000,
+ [VDD_LOW] = 100000000,
+ [VDD_NOMINAL] = 128000000},
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s3_clk_src = {
+ .cmd_rcgr = 0x1f4d8,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s3_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s4_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s4_clk_src",
+ .parent_names = gcc_parent_names_1,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 75000000,
+ [VDD_LOW] = 100000000,
+ [VDD_NOMINAL] = 128000000},
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s4_clk_src = {
+ .cmd_rcgr = 0x1f608,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s4_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s5_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s5_clk_src",
+ .parent_names = gcc_parent_names_1,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 75000000,
+ [VDD_LOW] = 100000000,
+ [VDD_NOMINAL] = 128000000},
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s5_clk_src = {
+ .cmd_rcgr = 0x1f738,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s5_clk_src_init,
+};
+
+static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk_src[] = {
+ F(144000, P_BI_TCXO, 16, 3, 25),
+ F(400000, P_BI_TCXO, 12, 1, 4),
+ F(20000000, P_GPLL0_OUT_AUX2, 5, 1, 3),
+ F(25000000, P_GPLL0_OUT_AUX2, 6, 1, 2),
+ F(50000000, P_GPLL0_OUT_AUX2, 6, 0, 0),
+ F(100000000, P_GPLL0_OUT_AUX2, 3, 0, 0),
+ F(192000000, P_GPLL6_OUT_MAIN, 2, 0, 0),
+ F(384000000, P_GPLL6_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_sdcc1_apps_clk_src = {
+ .cmd_rcgr = 0x38028,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_sdcc1_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_apps_clk_src",
+ .parent_names = gcc_parent_names_1,
+ .num_parents = 5,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .flags = CLK_OPS_PARENT_ENABLE,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 100000000,
+ [VDD_LOW_L1] = 384000000},
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_sdcc1_ice_core_clk_src[] = {
+ F(75000000, P_GPLL0_OUT_AUX2, 4, 0, 0),
+ F(100000000, P_GPLL0_OUT_AUX2, 3, 0, 0),
+ F(150000000, P_GPLL0_OUT_AUX2, 2, 0, 0),
+ F(200000000, P_GPLL0_OUT_EARLY, 3, 0, 0),
+ F(300000000, P_GPLL0_OUT_AUX2, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_sdcc1_ice_core_clk_src = {
+ .cmd_rcgr = 0x38010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_sdcc1_ice_core_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_ice_core_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 100000000,
+ [VDD_LOW] = 150000000,
+ [VDD_LOW_L1] = 300000000},
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = {
+ F(400000, P_BI_TCXO, 12, 1, 4),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(25000000, P_GPLL0_OUT_AUX2, 12, 0, 0),
+ F(50000000, P_GPLL0_OUT_AUX2, 6, 0, 0),
+ F(100000000, P_GPLL0_OUT_AUX2, 3, 0, 0),
+ F(202000000, P_GPLL7_OUT_MAIN, 4, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_sdcc2_apps_clk_src = {
+ .cmd_rcgr = 0x1e00c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_11,
+ .freq_tbl = ftbl_gcc_sdcc2_apps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc2_apps_clk_src",
+ .parent_names = gcc_parent_names_11,
+ .num_parents = 6,
+ .ops = &clk_rcg2_ops,
+ .flags = CLK_OPS_PARENT_ENABLE,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 100000000,
+ [VDD_LOW_L1] = 202000000},
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_ufs_phy_axi_clk_src[] = {
+ F(25000000, P_GPLL0_OUT_AUX2, 12, 0, 0),
+ F(50000000, P_GPLL0_OUT_AUX2, 6, 0, 0),
+ F(100000000, P_GPLL0_OUT_AUX2, 3, 0, 0),
+ F(200000000, P_GPLL0_OUT_EARLY, 3, 0, 0),
+ F(240000000, P_GPLL0_OUT_EARLY, 2.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_ufs_phy_axi_clk_src = {
+ .cmd_rcgr = 0x45020,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_ufs_phy_axi_clk_src,
+ .enable_safe_config = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_phy_axi_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 50000000,
+ [VDD_LOW] = 100000000,
+ [VDD_NOMINAL] = 200000000,
+ [VDD_HIGH] = 240000000},
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_ufs_phy_ice_core_clk_src[] = {
+ F(37500000, P_GPLL0_OUT_AUX2, 8, 0, 0),
+ F(75000000, P_GPLL0_OUT_AUX2, 4, 0, 0),
+ F(150000000, P_GPLL0_OUT_AUX2, 2, 0, 0),
+ F(300000000, P_GPLL0_OUT_AUX2, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_ufs_phy_ice_core_clk_src = {
+ .cmd_rcgr = 0x45048,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_ufs_phy_ice_core_clk_src,
+ .enable_safe_config = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_phy_ice_core_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 75000000,
+ [VDD_LOW] = 150000000,
+ [VDD_NOMINAL] = 300000000},
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_ufs_phy_phy_aux_clk_src[] = {
+ F(9600000, P_BI_TCXO, 2, 0, 0),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_ufs_phy_phy_aux_clk_src = {
+ .cmd_rcgr = 0x4507c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_ufs_phy_phy_aux_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_phy_phy_aux_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 19200000},
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_ufs_phy_unipro_core_clk_src[] = {
+ F(37500000, P_GPLL0_OUT_AUX2, 8, 0, 0),
+ F(75000000, P_GPLL0_OUT_AUX2, 4, 0, 0),
+ F(150000000, P_GPLL0_OUT_AUX2, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_ufs_phy_unipro_core_clk_src = {
+ .cmd_rcgr = 0x45060,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_ufs_phy_unipro_core_clk_src,
+ .enable_safe_config = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_phy_unipro_core_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 37500000,
+ [VDD_LOW] = 75000000,
+ [VDD_NOMINAL] = 150000000},
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_usb30_prim_master_clk_src[] = {
+ F(66666667, P_GPLL0_OUT_AUX2, 4.5, 0, 0),
+ F(133333333, P_GPLL0_OUT_EARLY, 4.5, 0, 0),
+ F(200000000, P_GPLL0_OUT_EARLY, 3, 0, 0),
+ F(240000000, P_GPLL0_OUT_EARLY, 2.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_usb30_prim_master_clk_src = {
+ .cmd_rcgr = 0x1a01c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_usb30_prim_master_clk_src,
+ .enable_safe_config = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_usb30_prim_master_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 66666667,
+ [VDD_LOW] = 133333333,
+ [VDD_NOMINAL] = 200000000,
+ [VDD_HIGH] = 240000000},
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_usb30_prim_mock_utmi_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_usb30_prim_mock_utmi_clk_src = {
+ .cmd_rcgr = 0x1a034,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_usb30_prim_mock_utmi_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_usb30_prim_mock_utmi_clk_src",
+ .parent_names = gcc_parent_names_0,
+ .num_parents = 4,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 19200000},
+ },
+};
+
+static struct clk_rcg2 gcc_usb3_prim_phy_aux_clk_src = {
+ .cmd_rcgr = 0x1a060,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_12,
+ .freq_tbl = ftbl_gcc_usb30_prim_mock_utmi_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_usb3_prim_phy_aux_clk_src",
+ .parent_names = gcc_parent_names_12,
+ .num_parents = 3,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 19200000},
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_video_venus_clk_src[] = {
+ F(133000000, P_GPLL11_OUT_MAIN, 4.5, 0, 0),
+ F(240000000, P_GPLL11_OUT_MAIN, 2.5, 0, 0),
+ F(300000000, P_GPLL11_OUT_MAIN, 2, 0, 0),
+ F(384000000, P_GPLL11_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_video_venus_clk_src = {
+ .cmd_rcgr = 0x58060,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_13,
+ .freq_tbl = ftbl_gcc_video_venus_clk_src,
+ .enable_safe_config = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gcc_video_venus_clk_src",
+ .parent_names = gcc_parent_names_13,
+ .num_parents = 5,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ .vdd_class = &vdd_cx,
+ .num_rate_max = VDD_NUM,
+ .rate_max = (unsigned long[VDD_NUM]) {
+ [VDD_LOWER] = 133000000,
+ [VDD_LOW] = 240000000,
+ [VDD_LOW_L1] = 300000000,
+ [VDD_NOMINAL] = 384000000},
+ },
+};
+
+static struct clk_branch gcc_ahb2phy_csi_clk = {
+ .halt_reg = 0x1d004,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x1d004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x1d004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ahb2phy_csi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ahb2phy_usb_clk = {
+ .halt_reg = 0x1d008,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x1d008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x1d008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ahb2phy_usb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_bimc_gpu_axi_clk = {
+ .halt_reg = 0x71154,
+ .halt_check = BRANCH_HALT_DELAY,
+ .hwcg_reg = 0x71154,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x71154,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_bimc_gpu_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_boot_rom_ahb_clk = {
+ .halt_reg = 0x23004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x23004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(10),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_boot_rom_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cam_throttle_nrt_clk = {
+ .halt_reg = 0x17070,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x17070,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(27),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_cam_throttle_nrt_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cam_throttle_rt_clk = {
+ .halt_reg = 0x1706c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x1706c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(26),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_cam_throttle_rt_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camera_ahb_clk = {
+ .halt_reg = 0x17008,
+ .halt_check = BRANCH_HALT_DELAY,
+ .hwcg_reg = 0x17008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x17008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camera_ahb_clk",
+ .flags = CLK_IS_CRITICAL,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camera_xo_clk = {
+ .halt_reg = 0x17028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x17028,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camera_xo_clk",
+ .flags = CLK_IS_CRITICAL,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_axi_clk = {
+ .halt_reg = 0x58044,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x58044,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_axi_clk",
+ .parent_names = (const char *[]){
+ "gcc_camss_axi_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_camnoc_atb_clk = {
+ .halt_reg = 0x5804c,
+ .halt_check = BRANCH_HALT_DELAY,
+ .hwcg_reg = 0x5804c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x5804c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_camnoc_atb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_camnoc_nts_xo_clk = {
+ .halt_reg = 0x58050,
+ .halt_check = BRANCH_HALT_DELAY,
+ .hwcg_reg = 0x58050,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x58050,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_camnoc_nts_xo_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_cci_0_clk = {
+ .halt_reg = 0x56018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x56018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_cci_0_clk",
+ .parent_names = (const char *[]){
+ "gcc_camss_cci_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_cphy_0_clk = {
+ .halt_reg = 0x52088,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x52088,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_cphy_0_clk",
+ .parent_names = (const char *[]){
+ "gcc_camss_tfe_cphy_rx_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_cphy_1_clk = {
+ .halt_reg = 0x5208c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5208c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_cphy_1_clk",
+ .parent_names = (const char *[]){
+ "gcc_camss_tfe_cphy_rx_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_cphy_2_clk = {
+ .halt_reg = 0x52090,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x52090,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_cphy_2_clk",
+ .parent_names = (const char *[]){
+ "gcc_camss_tfe_cphy_rx_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi0phytimer_clk = {
+ .halt_reg = 0x59018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x59018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi0phytimer_clk",
+ .parent_names = (const char *[]){
+ "gcc_camss_csi0phytimer_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi1phytimer_clk = {
+ .halt_reg = 0x59034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x59034,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi1phytimer_clk",
+ .parent_names = (const char *[]){
+ "gcc_camss_csi1phytimer_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi2phytimer_clk = {
+ .halt_reg = 0x59050,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x59050,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi2phytimer_clk",
+ .parent_names = (const char *[]){
+ "gcc_camss_csi2phytimer_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_mclk0_clk = {
+ .halt_reg = 0x51018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x51018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_mclk0_clk",
+ .parent_names = (const char *[]){
+ "gcc_camss_mclk0_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_mclk1_clk = {
+ .halt_reg = 0x51034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x51034,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_mclk1_clk",
+ .parent_names = (const char *[]){
+ "gcc_camss_mclk1_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_mclk2_clk = {
+ .halt_reg = 0x51050,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x51050,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_mclk2_clk",
+ .parent_names = (const char *[]){
+ "gcc_camss_mclk2_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_mclk3_clk = {
+ .halt_reg = 0x5106c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5106c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_mclk3_clk",
+ .parent_names = (const char *[]){
+ "gcc_camss_mclk3_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_nrt_axi_clk = {
+ .halt_reg = 0x58054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x58054,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_nrt_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_ope_ahb_clk = {
+ .halt_reg = 0x5503c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5503c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_ope_ahb_clk",
+ .parent_names = (const char *[]){
+ "gcc_camss_ope_ahb_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_ope_clk = {
+ .halt_reg = 0x5501c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5501c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_ope_clk",
+ .parent_names = (const char *[]){
+ "gcc_camss_ope_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_rt_axi_clk = {
+ .halt_reg = 0x5805c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5805c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_rt_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_tfe_0_clk = {
+ .halt_reg = 0x5201c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5201c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_tfe_0_clk",
+ .parent_names = (const char *[]){
+ "gcc_camss_tfe_0_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_tfe_0_cphy_rx_clk = {
+ .halt_reg = 0x5207c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5207c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_tfe_0_cphy_rx_clk",
+ .parent_names = (const char *[]){
+ "gcc_camss_tfe_cphy_rx_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_tfe_0_csid_clk = {
+ .halt_reg = 0x520ac,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x520ac,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_tfe_0_csid_clk",
+ .parent_names = (const char *[]){
+ "gcc_camss_tfe_0_csid_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_tfe_1_clk = {
+ .halt_reg = 0x5203c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5203c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_tfe_1_clk",
+ .parent_names = (const char *[]){
+ "gcc_camss_tfe_1_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_tfe_1_cphy_rx_clk = {
+ .halt_reg = 0x52080,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x52080,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_tfe_1_cphy_rx_clk",
+ .parent_names = (const char *[]){
+ "gcc_camss_tfe_cphy_rx_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_tfe_1_csid_clk = {
+ .halt_reg = 0x520cc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x520cc,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_tfe_1_csid_clk",
+ .parent_names = (const char *[]){
+ "gcc_camss_tfe_1_csid_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_tfe_2_clk = {
+ .halt_reg = 0x5205c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5205c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_tfe_2_clk",
+ .parent_names = (const char *[]){
+ "gcc_camss_tfe_2_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_tfe_2_cphy_rx_clk = {
+ .halt_reg = 0x52084,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x52084,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_tfe_2_cphy_rx_clk",
+ .parent_names = (const char *[]){
+ "gcc_camss_tfe_cphy_rx_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_tfe_2_csid_clk = {
+ .halt_reg = 0x520ec,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x520ec,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_tfe_2_csid_clk",
+ .parent_names = (const char *[]){
+ "gcc_camss_tfe_2_csid_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_top_ahb_clk = {
+ .halt_reg = 0x58028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x58028,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_top_ahb_clk",
+ .parent_names = (const char *[]){
+ "gcc_camss_top_ahb_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cfg_noc_usb3_prim_axi_clk = {
+ .halt_reg = 0x1a084,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x1a084,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x1a084,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_cfg_noc_usb3_prim_axi_clk",
+ .parent_names = (const char *[]){
+ "gcc_usb30_prim_master_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cpuss_ahb_clk = {
+ .halt_reg = 0x2b000,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2b000,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(21),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_cpuss_ahb_clk",
+ .flags = CLK_IS_CRITICAL,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cpuss_gnoc_clk = {
+ .halt_reg = 0x2b004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2b004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(22),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_cpuss_gnoc_clk",
+ .flags = CLK_IS_CRITICAL,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cpuss_throttle_core_clk = {
+ .halt_reg = 0x2b180,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2b180,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(30),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_cpuss_throttle_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cpuss_throttle_xo_clk = {
+ .halt_reg = 0x2b17c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2b17c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_cpuss_throttle_xo_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_disp_ahb_clk = {
+ .halt_reg = 0x1700c,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x1700c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x1700c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_disp_ahb_clk",
+ .flags = CLK_IS_CRITICAL,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_disp_gpll0_div_clk_src = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(20),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_disp_gpll0_div_clk_src",
+ .parent_names = (const char *[]){
+ "gpll0",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_disp_hf_axi_clk = {
+ .halt_reg = 0x17020,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x17020,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x17020,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_disp_hf_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_disp_throttle_core_clk = {
+ .halt_reg = 0x17064,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x17064,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(5),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_disp_throttle_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_disp_xo_clk = {
+ .halt_reg = 0x1702c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1702c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_disp_xo_clk",
+ .flags = CLK_IS_CRITICAL,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp1_clk = {
+ .halt_reg = 0x4d000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4d000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gp1_clk",
+ .parent_names = (const char *[]){
+ "gcc_gp1_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp2_clk = {
+ .halt_reg = 0x4e000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4e000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gp2_clk",
+ .parent_names = (const char *[]){
+ "gcc_gp2_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp3_clk = {
+ .halt_reg = 0x4f000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4f000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gp3_clk",
+ .parent_names = (const char *[]){
+ "gcc_gp3_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_cfg_ahb_clk = {
+ .halt_reg = 0x36004,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x36004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x36004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gpu_cfg_ahb_clk",
+ .flags = CLK_IS_CRITICAL,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_gpll0_clk_src = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(15),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gpu_gpll0_clk_src",
+ .parent_names = (const char *[]){
+ "gpll0",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_gpll0_div_clk_src = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(16),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gpu_gpll0_div_clk_src",
+ .parent_names = (const char *[]){
+ "gpll0_out_aux2",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_iref_clk = {
+ .halt_reg = 0x36100,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x36100,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gpu_iref_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_memnoc_gfx_clk = {
+ .halt_reg = 0x3600c,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x3600c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x3600c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gpu_memnoc_gfx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_snoc_dvm_gfx_clk = {
+ .halt_reg = 0x36018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x36018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gpu_snoc_dvm_gfx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_throttle_core_clk = {
+ .halt_reg = 0x36048,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x36048,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(31),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gpu_throttle_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_throttle_xo_clk = {
+ .halt_reg = 0x36044,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x36044,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_gpu_throttle_xo_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm2_clk = {
+ .halt_reg = 0x2000c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2000c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pdm2_clk",
+ .parent_names = (const char *[]){
+ "gcc_pdm2_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm_ahb_clk = {
+ .halt_reg = 0x20004,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x20004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x20004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pdm_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm_xo4_clk = {
+ .halt_reg = 0x20008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x20008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pdm_xo4_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_prng_ahb_clk = {
+ .halt_reg = 0x21004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x21004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(13),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_prng_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_camera_nrt_ahb_clk = {
+ .halt_reg = 0x17014,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x17014,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qmip_camera_nrt_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_camera_rt_ahb_clk = {
+ .halt_reg = 0x17060,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x17060,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(2),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qmip_camera_rt_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_cpuss_cfg_ahb_clk = {
+ .halt_reg = 0x2b178,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2b178,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(18),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qmip_cpuss_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_disp_ahb_clk = {
+ .halt_reg = 0x17018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x17018,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(1),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qmip_disp_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_gpu_cfg_ahb_clk = {
+ .halt_reg = 0x36040,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x36040,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qmip_gpu_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_video_vcodec_ahb_clk = {
+ .halt_reg = 0x17010,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x17010,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(25),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qmip_video_vcodec_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_core_2x_clk = {
+ .halt_reg = 0x1f014,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(9),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap0_core_2x_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_core_clk = {
+ .halt_reg = 0x1f00c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(8),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap0_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s0_clk = {
+ .halt_reg = 0x1f144,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(10),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap0_s0_clk",
+ .parent_names = (const char *[]){
+ "gcc_qupv3_wrap0_s0_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s1_clk = {
+ .halt_reg = 0x1f274,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(11),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap0_s1_clk",
+ .parent_names = (const char *[]){
+ "gcc_qupv3_wrap0_s1_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s2_clk = {
+ .halt_reg = 0x1f3a4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(12),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap0_s2_clk",
+ .parent_names = (const char *[]){
+ "gcc_qupv3_wrap0_s2_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s3_clk = {
+ .halt_reg = 0x1f4d4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(13),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap0_s3_clk",
+ .parent_names = (const char *[]){
+ "gcc_qupv3_wrap0_s3_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s4_clk = {
+ .halt_reg = 0x1f604,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(14),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap0_s4_clk",
+ .parent_names = (const char *[]){
+ "gcc_qupv3_wrap0_s4_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s5_clk = {
+ .halt_reg = 0x1f734,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(15),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap0_s5_clk",
+ .parent_names = (const char *[]){
+ "gcc_qupv3_wrap0_s5_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_0_m_ahb_clk = {
+ .halt_reg = 0x1f004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x1f004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(6),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap_0_m_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_0_s_ahb_clk = {
+ .halt_reg = 0x1f008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x1f008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7900c,
+ .enable_mask = BIT(7),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qupv3_wrap_0_s_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_ahb_clk = {
+ .halt_reg = 0x38008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x38008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_apps_clk = {
+ .halt_reg = 0x38004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x38004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_apps_clk",
+ .parent_names = (const char *[]){
+ "gcc_sdcc1_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT | CLK_ENABLE_HAND_OFF,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_ice_core_clk = {
+ .halt_reg = 0x3800c,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x3800c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x3800c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc1_ice_core_clk",
+ .parent_names = (const char *[]){
+ "gcc_sdcc1_ice_core_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc2_ahb_clk = {
+ .halt_reg = 0x1e008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1e008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc2_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc2_apps_clk = {
+ .halt_reg = 0x1e004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1e004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sdcc2_apps_clk",
+ .parent_names = (const char *[]){
+ "gcc_sdcc2_apps_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sys_noc_cpuss_ahb_clk = {
+ .halt_reg = 0x2b06c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2b06c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sys_noc_cpuss_ahb_clk",
+ .flags = CLK_IS_CRITICAL,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sys_noc_ufs_phy_axi_clk = {
+ .halt_reg = 0x45098,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x45098,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sys_noc_ufs_phy_axi_clk",
+ .parent_names = (const char *[]){
+ "gcc_ufs_phy_axi_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sys_noc_usb3_prim_axi_clk = {
+ .halt_reg = 0x1a080,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x1a080,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x1a080,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_sys_noc_usb3_prim_axi_clk",
+ .parent_names = (const char *[]){
+ "gcc_usb30_prim_master_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_ahb_clk = {
+ .halt_reg = 0x45014,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x45014,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x45014,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_phy_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_axi_clk = {
+ .halt_reg = 0x45010,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x45010,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x45010,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_phy_axi_clk",
+ .parent_names = (const char *[]){
+ "gcc_ufs_phy_axi_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_ice_core_clk = {
+ .halt_reg = 0x45044,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x45044,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x45044,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_phy_ice_core_clk",
+ .parent_names = (const char *[]){
+ "gcc_ufs_phy_ice_core_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_phy_aux_clk = {
+ .halt_reg = 0x45078,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x45078,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x45078,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_phy_phy_aux_clk",
+ .parent_names = (const char *[]){
+ "gcc_ufs_phy_phy_aux_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_rx_symbol_0_clk = {
+ .halt_reg = 0x4501c,
+ .halt_check = BRANCH_HALT_SKIP,
+ .clkr = {
+ .enable_reg = 0x4501c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_phy_rx_symbol_0_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_tx_symbol_0_clk = {
+ .halt_reg = 0x45018,
+ .halt_check = BRANCH_HALT_SKIP,
+ .clkr = {
+ .enable_reg = 0x45018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_phy_tx_symbol_0_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_unipro_core_clk = {
+ .halt_reg = 0x45040,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x45040,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x45040,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_ufs_phy_unipro_core_clk",
+ .parent_names = (const char *[]){
+ "gcc_ufs_phy_unipro_core_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_prim_master_clk = {
+ .halt_reg = 0x1a010,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1a010,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb30_prim_master_clk",
+ .parent_names = (const char *[]){
+ "gcc_usb30_prim_master_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_prim_mock_utmi_clk = {
+ .halt_reg = 0x1a018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1a018,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb30_prim_mock_utmi_clk",
+ .parent_names = (const char *[]){
+ "gcc_usb30_prim_mock_utmi_postdiv_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_prim_sleep_clk = {
+ .halt_reg = 0x1a014,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1a014,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb30_prim_sleep_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_prim_clkref_clk = {
+ .halt_reg = 0x9f000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9f000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb3_prim_clkref_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_prim_phy_com_aux_clk = {
+ .halt_reg = 0x1a054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1a054,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb3_prim_phy_com_aux_clk",
+ .parent_names = (const char *[]){
+ "gcc_usb3_prim_phy_aux_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_prim_phy_pipe_clk = {
+ .halt_reg = 0x1a058,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x1a058,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x1a058,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb3_prim_phy_pipe_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_vcodec0_axi_clk = {
+ .halt_reg = 0x6e008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6e008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_vcodec0_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_venus_ahb_clk = {
+ .halt_reg = 0x6e010,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6e010,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_venus_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_venus_ctl_axi_clk = {
+ .halt_reg = 0x6e004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6e004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_venus_ctl_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_video_ahb_clk = {
+ .halt_reg = 0x17004,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x17004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x17004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_video_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_video_axi0_clk = {
+ .halt_reg = 0x1701c,
+ .halt_check = BRANCH_HALT,
+ .hwcg_reg = 0x1701c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x1701c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_video_axi0_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_video_throttle_core_clk = {
+ .halt_reg = 0x17068,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x17068,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x79004,
+ .enable_mask = BIT(28),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_video_throttle_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_video_vcodec0_sys_clk = {
+ .halt_reg = 0x580a4,
+ .halt_check = BRANCH_HALT_DELAY,
+ .hwcg_reg = 0x580a4,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x580a4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_video_vcodec0_sys_clk",
+ .parent_names = (const char *[]){
+ "gcc_video_venus_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_video_venus_ctl_clk = {
+ .halt_reg = 0x5808c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x5808c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_video_venus_ctl_clk",
+ .parent_names = (const char *[]){
+ "gcc_video_venus_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_video_xo_clk = {
+ .halt_reg = 0x17024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x17024,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_video_xo_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_regmap *gcc_bengal_clocks[] = {
+ [GCC_AHB2PHY_CSI_CLK] = &gcc_ahb2phy_csi_clk.clkr,
+ [GCC_AHB2PHY_USB_CLK] = &gcc_ahb2phy_usb_clk.clkr,
+ [GCC_BIMC_GPU_AXI_CLK] = &gcc_bimc_gpu_axi_clk.clkr,
+ [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr,
+ [GCC_CAM_THROTTLE_NRT_CLK] = &gcc_cam_throttle_nrt_clk.clkr,
+ [GCC_CAM_THROTTLE_RT_CLK] = &gcc_cam_throttle_rt_clk.clkr,
+ [GCC_CAMERA_AHB_CLK] = &gcc_camera_ahb_clk.clkr,
+ [GCC_CAMERA_XO_CLK] = &gcc_camera_xo_clk.clkr,
+ [GCC_CAMSS_AXI_CLK] = &gcc_camss_axi_clk.clkr,
+ [GCC_CAMSS_AXI_CLK_SRC] = &gcc_camss_axi_clk_src.clkr,
+ [GCC_CAMSS_CAMNOC_ATB_CLK] = &gcc_camss_camnoc_atb_clk.clkr,
+ [GCC_CAMSS_CAMNOC_NTS_XO_CLK] = &gcc_camss_camnoc_nts_xo_clk.clkr,
+ [GCC_CAMSS_CCI_0_CLK] = &gcc_camss_cci_0_clk.clkr,
+ [GCC_CAMSS_CCI_CLK_SRC] = &gcc_camss_cci_clk_src.clkr,
+ [GCC_CAMSS_CPHY_0_CLK] = &gcc_camss_cphy_0_clk.clkr,
+ [GCC_CAMSS_CPHY_1_CLK] = &gcc_camss_cphy_1_clk.clkr,
+ [GCC_CAMSS_CPHY_2_CLK] = &gcc_camss_cphy_2_clk.clkr,
+ [GCC_CAMSS_CSI0PHYTIMER_CLK] = &gcc_camss_csi0phytimer_clk.clkr,
+ [GCC_CAMSS_CSI0PHYTIMER_CLK_SRC] = &gcc_camss_csi0phytimer_clk_src.clkr,
+ [GCC_CAMSS_CSI1PHYTIMER_CLK] = &gcc_camss_csi1phytimer_clk.clkr,
+ [GCC_CAMSS_CSI1PHYTIMER_CLK_SRC] = &gcc_camss_csi1phytimer_clk_src.clkr,
+ [GCC_CAMSS_CSI2PHYTIMER_CLK] = &gcc_camss_csi2phytimer_clk.clkr,
+ [GCC_CAMSS_CSI2PHYTIMER_CLK_SRC] = &gcc_camss_csi2phytimer_clk_src.clkr,
+ [GCC_CAMSS_MCLK0_CLK] = &gcc_camss_mclk0_clk.clkr,
+ [GCC_CAMSS_MCLK0_CLK_SRC] = &gcc_camss_mclk0_clk_src.clkr,
+ [GCC_CAMSS_MCLK1_CLK] = &gcc_camss_mclk1_clk.clkr,
+ [GCC_CAMSS_MCLK1_CLK_SRC] = &gcc_camss_mclk1_clk_src.clkr,
+ [GCC_CAMSS_MCLK2_CLK] = &gcc_camss_mclk2_clk.clkr,
+ [GCC_CAMSS_MCLK2_CLK_SRC] = &gcc_camss_mclk2_clk_src.clkr,
+ [GCC_CAMSS_MCLK3_CLK] = &gcc_camss_mclk3_clk.clkr,
+ [GCC_CAMSS_MCLK3_CLK_SRC] = &gcc_camss_mclk3_clk_src.clkr,
+ [GCC_CAMSS_NRT_AXI_CLK] = &gcc_camss_nrt_axi_clk.clkr,
+ [GCC_CAMSS_OPE_AHB_CLK] = &gcc_camss_ope_ahb_clk.clkr,
+ [GCC_CAMSS_OPE_AHB_CLK_SRC] = &gcc_camss_ope_ahb_clk_src.clkr,
+ [GCC_CAMSS_OPE_CLK] = &gcc_camss_ope_clk.clkr,
+ [GCC_CAMSS_OPE_CLK_SRC] = &gcc_camss_ope_clk_src.clkr,
+ [GCC_CAMSS_RT_AXI_CLK] = &gcc_camss_rt_axi_clk.clkr,
+ [GCC_CAMSS_TFE_0_CLK] = &gcc_camss_tfe_0_clk.clkr,
+ [GCC_CAMSS_TFE_0_CLK_SRC] = &gcc_camss_tfe_0_clk_src.clkr,
+ [GCC_CAMSS_TFE_0_CPHY_RX_CLK] = &gcc_camss_tfe_0_cphy_rx_clk.clkr,
+ [GCC_CAMSS_TFE_0_CSID_CLK] = &gcc_camss_tfe_0_csid_clk.clkr,
+ [GCC_CAMSS_TFE_0_CSID_CLK_SRC] = &gcc_camss_tfe_0_csid_clk_src.clkr,
+ [GCC_CAMSS_TFE_1_CLK] = &gcc_camss_tfe_1_clk.clkr,
+ [GCC_CAMSS_TFE_1_CLK_SRC] = &gcc_camss_tfe_1_clk_src.clkr,
+ [GCC_CAMSS_TFE_1_CPHY_RX_CLK] = &gcc_camss_tfe_1_cphy_rx_clk.clkr,
+ [GCC_CAMSS_TFE_1_CSID_CLK] = &gcc_camss_tfe_1_csid_clk.clkr,
+ [GCC_CAMSS_TFE_1_CSID_CLK_SRC] = &gcc_camss_tfe_1_csid_clk_src.clkr,
+ [GCC_CAMSS_TFE_2_CLK] = &gcc_camss_tfe_2_clk.clkr,
+ [GCC_CAMSS_TFE_2_CLK_SRC] = &gcc_camss_tfe_2_clk_src.clkr,
+ [GCC_CAMSS_TFE_2_CPHY_RX_CLK] = &gcc_camss_tfe_2_cphy_rx_clk.clkr,
+ [GCC_CAMSS_TFE_2_CSID_CLK] = &gcc_camss_tfe_2_csid_clk.clkr,
+ [GCC_CAMSS_TFE_2_CSID_CLK_SRC] = &gcc_camss_tfe_2_csid_clk_src.clkr,
+ [GCC_CAMSS_TFE_CPHY_RX_CLK_SRC] = &gcc_camss_tfe_cphy_rx_clk_src.clkr,
+ [GCC_CAMSS_TOP_AHB_CLK] = &gcc_camss_top_ahb_clk.clkr,
+ [GCC_CAMSS_TOP_AHB_CLK_SRC] = &gcc_camss_top_ahb_clk_src.clkr,
+ [GCC_CFG_NOC_USB3_PRIM_AXI_CLK] = &gcc_cfg_noc_usb3_prim_axi_clk.clkr,
+ [GCC_CPUSS_AHB_CLK] = &gcc_cpuss_ahb_clk.clkr,
+ [GCC_CPUSS_GNOC_CLK] = &gcc_cpuss_gnoc_clk.clkr,
+ [GCC_CPUSS_THROTTLE_CORE_CLK] = &gcc_cpuss_throttle_core_clk.clkr,
+ [GCC_CPUSS_THROTTLE_XO_CLK] = &gcc_cpuss_throttle_xo_clk.clkr,
+ [GCC_DISP_AHB_CLK] = &gcc_disp_ahb_clk.clkr,
+ [GCC_DISP_GPLL0_DIV_CLK_SRC] = &gcc_disp_gpll0_div_clk_src.clkr,
+ [GCC_DISP_HF_AXI_CLK] = &gcc_disp_hf_axi_clk.clkr,
+ [GCC_DISP_THROTTLE_CORE_CLK] = &gcc_disp_throttle_core_clk.clkr,
+ [GCC_DISP_XO_CLK] = &gcc_disp_xo_clk.clkr,
+ [GCC_GP1_CLK] = &gcc_gp1_clk.clkr,
+ [GCC_GP1_CLK_SRC] = &gcc_gp1_clk_src.clkr,
+ [GCC_GP2_CLK] = &gcc_gp2_clk.clkr,
+ [GCC_GP2_CLK_SRC] = &gcc_gp2_clk_src.clkr,
+ [GCC_GP3_CLK] = &gcc_gp3_clk.clkr,
+ [GCC_GP3_CLK_SRC] = &gcc_gp3_clk_src.clkr,
+ [GCC_GPU_CFG_AHB_CLK] = &gcc_gpu_cfg_ahb_clk.clkr,
+ [GCC_GPU_GPLL0_CLK_SRC] = &gcc_gpu_gpll0_clk_src.clkr,
+ [GCC_GPU_GPLL0_DIV_CLK_SRC] = &gcc_gpu_gpll0_div_clk_src.clkr,
+ [GCC_GPU_IREF_CLK] = &gcc_gpu_iref_clk.clkr,
+ [GCC_GPU_MEMNOC_GFX_CLK] = &gcc_gpu_memnoc_gfx_clk.clkr,
+ [GCC_GPU_SNOC_DVM_GFX_CLK] = &gcc_gpu_snoc_dvm_gfx_clk.clkr,
+ [GCC_GPU_THROTTLE_CORE_CLK] = &gcc_gpu_throttle_core_clk.clkr,
+ [GCC_GPU_THROTTLE_XO_CLK] = &gcc_gpu_throttle_xo_clk.clkr,
+ [GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr,
+ [GCC_PDM2_CLK_SRC] = &gcc_pdm2_clk_src.clkr,
+ [GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr,
+ [GCC_PDM_XO4_CLK] = &gcc_pdm_xo4_clk.clkr,
+ [GCC_PRNG_AHB_CLK] = &gcc_prng_ahb_clk.clkr,
+ [GCC_QMIP_CAMERA_NRT_AHB_CLK] = &gcc_qmip_camera_nrt_ahb_clk.clkr,
+ [GCC_QMIP_CAMERA_RT_AHB_CLK] = &gcc_qmip_camera_rt_ahb_clk.clkr,
+ [GCC_QMIP_CPUSS_CFG_AHB_CLK] = &gcc_qmip_cpuss_cfg_ahb_clk.clkr,
+ [GCC_QMIP_DISP_AHB_CLK] = &gcc_qmip_disp_ahb_clk.clkr,
+ [GCC_QMIP_GPU_CFG_AHB_CLK] = &gcc_qmip_gpu_cfg_ahb_clk.clkr,
+ [GCC_QMIP_VIDEO_VCODEC_AHB_CLK] = &gcc_qmip_video_vcodec_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP0_CORE_2X_CLK] = &gcc_qupv3_wrap0_core_2x_clk.clkr,
+ [GCC_QUPV3_WRAP0_CORE_CLK] = &gcc_qupv3_wrap0_core_clk.clkr,
+ [GCC_QUPV3_WRAP0_S0_CLK] = &gcc_qupv3_wrap0_s0_clk.clkr,
+ [GCC_QUPV3_WRAP0_S0_CLK_SRC] = &gcc_qupv3_wrap0_s0_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S1_CLK] = &gcc_qupv3_wrap0_s1_clk.clkr,
+ [GCC_QUPV3_WRAP0_S1_CLK_SRC] = &gcc_qupv3_wrap0_s1_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S2_CLK] = &gcc_qupv3_wrap0_s2_clk.clkr,
+ [GCC_QUPV3_WRAP0_S2_CLK_SRC] = &gcc_qupv3_wrap0_s2_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S3_CLK] = &gcc_qupv3_wrap0_s3_clk.clkr,
+ [GCC_QUPV3_WRAP0_S3_CLK_SRC] = &gcc_qupv3_wrap0_s3_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S4_CLK] = &gcc_qupv3_wrap0_s4_clk.clkr,
+ [GCC_QUPV3_WRAP0_S4_CLK_SRC] = &gcc_qupv3_wrap0_s4_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S5_CLK] = &gcc_qupv3_wrap0_s5_clk.clkr,
+ [GCC_QUPV3_WRAP0_S5_CLK_SRC] = &gcc_qupv3_wrap0_s5_clk_src.clkr,
+ [GCC_QUPV3_WRAP_0_M_AHB_CLK] = &gcc_qupv3_wrap_0_m_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_0_S_AHB_CLK] = &gcc_qupv3_wrap_0_s_ahb_clk.clkr,
+ [GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr,
+ [GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr,
+ [GCC_SDCC1_APPS_CLK_SRC] = &gcc_sdcc1_apps_clk_src.clkr,
+ [GCC_SDCC1_ICE_CORE_CLK] = &gcc_sdcc1_ice_core_clk.clkr,
+ [GCC_SDCC1_ICE_CORE_CLK_SRC] = &gcc_sdcc1_ice_core_clk_src.clkr,
+ [GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr,
+ [GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr,
+ [GCC_SDCC2_APPS_CLK_SRC] = &gcc_sdcc2_apps_clk_src.clkr,
+ [GCC_SYS_NOC_CPUSS_AHB_CLK] = &gcc_sys_noc_cpuss_ahb_clk.clkr,
+ [GCC_SYS_NOC_UFS_PHY_AXI_CLK] = &gcc_sys_noc_ufs_phy_axi_clk.clkr,
+ [GCC_SYS_NOC_USB3_PRIM_AXI_CLK] = &gcc_sys_noc_usb3_prim_axi_clk.clkr,
+ [GCC_UFS_PHY_AHB_CLK] = &gcc_ufs_phy_ahb_clk.clkr,
+ [GCC_UFS_PHY_AXI_CLK] = &gcc_ufs_phy_axi_clk.clkr,
+ [GCC_UFS_PHY_AXI_CLK_SRC] = &gcc_ufs_phy_axi_clk_src.clkr,
+ [GCC_UFS_PHY_ICE_CORE_CLK] = &gcc_ufs_phy_ice_core_clk.clkr,
+ [GCC_UFS_PHY_ICE_CORE_CLK_SRC] = &gcc_ufs_phy_ice_core_clk_src.clkr,
+ [GCC_UFS_PHY_PHY_AUX_CLK] = &gcc_ufs_phy_phy_aux_clk.clkr,
+ [GCC_UFS_PHY_PHY_AUX_CLK_SRC] = &gcc_ufs_phy_phy_aux_clk_src.clkr,
+ [GCC_UFS_PHY_RX_SYMBOL_0_CLK] = &gcc_ufs_phy_rx_symbol_0_clk.clkr,
+ [GCC_UFS_PHY_TX_SYMBOL_0_CLK] = &gcc_ufs_phy_tx_symbol_0_clk.clkr,
+ [GCC_UFS_PHY_UNIPRO_CORE_CLK] = &gcc_ufs_phy_unipro_core_clk.clkr,
+ [GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC] =
+ &gcc_ufs_phy_unipro_core_clk_src.clkr,
+ [GCC_USB30_PRIM_MASTER_CLK] = &gcc_usb30_prim_master_clk.clkr,
+ [GCC_USB30_PRIM_MASTER_CLK_SRC] = &gcc_usb30_prim_master_clk_src.clkr,
+ [GCC_USB30_PRIM_MOCK_UTMI_CLK] = &gcc_usb30_prim_mock_utmi_clk.clkr,
+ [GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC] =
+ &gcc_usb30_prim_mock_utmi_clk_src.clkr,
+ [GCC_USB30_PRIM_MOCK_UTMI_POSTDIV_CLK_SRC] =
+ &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr,
+ [GCC_USB30_PRIM_SLEEP_CLK] = &gcc_usb30_prim_sleep_clk.clkr,
+ [GCC_USB3_PRIM_CLKREF_CLK] = &gcc_usb3_prim_clkref_clk.clkr,
+ [GCC_USB3_PRIM_PHY_AUX_CLK_SRC] = &gcc_usb3_prim_phy_aux_clk_src.clkr,
+ [GCC_USB3_PRIM_PHY_COM_AUX_CLK] = &gcc_usb3_prim_phy_com_aux_clk.clkr,
+ [GCC_USB3_PRIM_PHY_PIPE_CLK] = &gcc_usb3_prim_phy_pipe_clk.clkr,
+ [GCC_VCODEC0_AXI_CLK] = &gcc_vcodec0_axi_clk.clkr,
+ [GCC_VENUS_AHB_CLK] = &gcc_venus_ahb_clk.clkr,
+ [GCC_VENUS_CTL_AXI_CLK] = &gcc_venus_ctl_axi_clk.clkr,
+ [GCC_VIDEO_AHB_CLK] = &gcc_video_ahb_clk.clkr,
+ [GCC_VIDEO_AXI0_CLK] = &gcc_video_axi0_clk.clkr,
+ [GCC_VIDEO_THROTTLE_CORE_CLK] = &gcc_video_throttle_core_clk.clkr,
+ [GCC_VIDEO_VCODEC0_SYS_CLK] = &gcc_video_vcodec0_sys_clk.clkr,
+ [GCC_VIDEO_VENUS_CLK_SRC] = &gcc_video_venus_clk_src.clkr,
+ [GCC_VIDEO_VENUS_CTL_CLK] = &gcc_video_venus_ctl_clk.clkr,
+ [GCC_VIDEO_XO_CLK] = &gcc_video_xo_clk.clkr,
+ [GPLL0] = &gpll0.clkr,
+ [GPLL0_OUT_AUX2] = &gpll0_out_aux2.clkr,
+ [GPLL0_OUT_MAIN] = &gpll0_out_main.clkr,
+ [GPLL10] = &gpll10.clkr,
+ [GPLL10_OUT_MAIN] = &gpll10_out_main.clkr,
+ [GPLL11] = &gpll11.clkr,
+ [GPLL11_OUT_MAIN] = &gpll11_out_main.clkr,
+ [GPLL3] = &gpll3.clkr,
+ [GPLL4] = &gpll4.clkr,
+ [GPLL4_OUT_MAIN] = &gpll4_out_main.clkr,
+ [GPLL6] = &gpll6.clkr,
+ [GPLL6_OUT_MAIN] = &gpll6_out_main.clkr,
+ [GPLL7] = &gpll7.clkr,
+ [GPLL7_OUT_MAIN] = &gpll7_out_main.clkr,
+ [GPLL8] = &gpll8.clkr,
+ [GPLL8_OUT_MAIN] = &gpll8_out_main.clkr,
+ [GPLL9] = &gpll9.clkr,
+ [GPLL9_OUT_MAIN] = &gpll9_out_main.clkr,
+};
+
+static const struct qcom_reset_map gcc_bengal_resets[] = {
+ [GCC_QUSB2PHY_PRIM_BCR] = { 0x1c000 },
+ [GCC_QUSB2PHY_SEC_BCR] = { 0x1c004 },
+ [GCC_UFS_PHY_BCR] = { 0x45000 },
+ [GCC_USB30_PRIM_BCR] = { 0x1a000 },
+ [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x1d000 },
+ [GCC_VCODEC0_BCR] = { 0x58094 },
+ [GCC_VENUS_BCR] = { 0x58078 },
+ [GCC_VIDEO_INTERFACE_BCR] = { 0x6e000 },
+};
+
+static const struct clk_rcg_dfs_data gcc_dfs_clocks[] = {
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s0_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s1_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s2_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s3_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s4_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s5_clk_src),
+};
+
+static const struct regmap_config gcc_bengal_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0xc7000,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc gcc_bengal_desc = {
+ .config = &gcc_bengal_regmap_config,
+ .clks = gcc_bengal_clocks,
+ .num_clks = ARRAY_SIZE(gcc_bengal_clocks),
+ .resets = gcc_bengal_resets,
+ .num_resets = ARRAY_SIZE(gcc_bengal_resets),
+};
+
+static const struct of_device_id gcc_bengal_match_table[] = {
+ { .compatible = "qcom,bengal-gcc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, gcc_bengal_match_table);
+
+static int gcc_bengal_probe(struct platform_device *pdev)
+{
+ struct regmap *regmap;
+ int ret;
+
+ regmap = qcom_cc_map(pdev, &gcc_bengal_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ vdd_cx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_cx");
+ if (IS_ERR(vdd_cx.regulator[0])) {
+ if (!(PTR_ERR(vdd_cx.regulator[0]) == -EPROBE_DEFER))
+ dev_err(&pdev->dev,
+ "Unable to get vdd_cx regulator\n");
+ return PTR_ERR(vdd_cx.regulator[0]);
+ }
+
+ vdd_cx_ao.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_cx_ao");
+ if (IS_ERR(vdd_cx_ao.regulator[0])) {
+ if (!(PTR_ERR(vdd_cx_ao.regulator[0]) == -EPROBE_DEFER))
+ dev_err(&pdev->dev,
+ "Unable to get vdd_cx_ao regulator\n");
+ return PTR_ERR(vdd_cx_ao.regulator[0]);
+ }
+
+ vdd_mx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_mx");
+ if (IS_ERR(vdd_mx.regulator[0])) {
+ if (!(PTR_ERR(vdd_mx.regulator[0]) == -EPROBE_DEFER))
+ dev_err(&pdev->dev,
+ "Unable to get vdd_mx regulator\n");
+ return PTR_ERR(vdd_mx.regulator[0]);
+ }
+
+ ret = qcom_cc_register_rcg_dfs(regmap, gcc_dfs_clocks,
+ ARRAY_SIZE(gcc_dfs_clocks));
+ if (ret)
+ return ret;
+
+ /* Disable the GPLL0 active input to NPU and GPU via MISC registers */
+
+ clk_alpha_pll_configure(&gpll8, regmap, &gpll8_config);
+ clk_alpha_pll_configure(&gpll9, regmap, &gpll9_config);
+ clk_alpha_pll_configure(&gpll10, regmap, &gpll10_config);
+ clk_alpha_pll_configure(&gpll11, regmap, &gpll11_config);
+
+ ret = qcom_cc_really_probe(pdev, &gcc_bengal_desc, regmap);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register GCC clocks\n");
+ return ret;
+ }
+
+ dev_info(&pdev->dev, "Registered GCC clocks\n");
+ return ret;
+}
+
+static struct platform_driver gcc_bengal_driver = {
+ .probe = gcc_bengal_probe,
+ .driver = {
+ .name = "gcc-bengal",
+ .of_match_table = gcc_bengal_match_table,
+ },
+};
+
+static int __init gcc_bengal_init(void)
+{
+ return platform_driver_register(&gcc_bengal_driver);
+}
+subsys_initcall(gcc_bengal_init);
+
+static void __exit gcc_bengal_exit(void)
+{
+ platform_driver_unregister(&gcc_bengal_driver);
+}
+module_exit(gcc_bengal_exit);
+
+MODULE_DESCRIPTION("QTI GCC BENGAL Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/qcom/vdd-level-bengal.h b/drivers/clk/qcom/vdd-level-bengal.h
new file mode 100644
index 0000000..619977f
--- /dev/null
+++ b/drivers/clk/qcom/vdd-level-bengal.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __DRIVERS_CLK_QCOM_VDD_LEVEL_H
+#define __DRIVERS_CLK_QCOM_VDD_LEVEL_H
+
+#include <linux/regulator/consumer.h>
+#include <dt-bindings/regulator/qcom,rpmh-regulator-levels.h>
+
+enum vdd_levels {
+ VDD_NONE,
+ VDD_MIN, /* MIN SVS */
+ VDD_LOWER, /* SVS2 */
+ VDD_LOW, /* SVS */
+ VDD_LOW_L1, /* SVSL1 */
+ VDD_NOMINAL, /* NOM */
+ VDD_NOMINAL_L1, /* NOM L1 */
+ VDD_HIGH, /* TURBO */
+ VDD_HIGH_L1, /* TURBO */
+ VDD_NUM,
+};
+
+static int vdd_corner[] = {
+ [VDD_NONE] = 0,
+ [VDD_MIN] = RPMH_REGULATOR_LEVEL_MIN_SVS,
+ [VDD_LOWER] = RPMH_REGULATOR_LEVEL_LOW_SVS,
+ [VDD_LOW] = RPMH_REGULATOR_LEVEL_SVS,
+ [VDD_LOW_L1] = RPMH_REGULATOR_LEVEL_SVS_L1,
+ [VDD_NOMINAL] = RPMH_REGULATOR_LEVEL_NOM,
+ [VDD_NOMINAL_L1] = RPMH_REGULATOR_LEVEL_NOM_L1,
+ [VDD_HIGH] = RPMH_REGULATOR_LEVEL_TURBO,
+ [VDD_HIGH_L1] = RPMH_REGULATOR_LEVEL_TURBO_L1,
+};
+
+#endif
diff --git a/drivers/clk/qcom/videocc-kona.c b/drivers/clk/qcom/videocc-kona.c
index abd28e7..a18ba3b 100644
--- a/drivers/clk/qcom/videocc-kona.c
+++ b/drivers/clk/qcom/videocc-kona.c
@@ -263,6 +263,8 @@ static struct clk_rcg2 video_cc_ahb_clk_src = {
.hid_width = 5,
.parent_map = video_cc_parent_map_0,
.freq_tbl = ftbl_video_cc_ahb_clk_src,
+ .enable_safe_config = true,
+ .flags = HW_CLK_CTRL_MODE,
.clkr.hw.init = &(struct clk_init_data){
.name = "video_cc_ahb_clk_src",
.parent_names = video_cc_parent_names_0_ao,
@@ -287,6 +289,7 @@ static struct clk_rcg2 video_cc_mvs0_clk_src = {
.parent_map = video_cc_parent_map_1,
.freq_tbl = ftbl_video_cc_mvs0_clk_src,
.enable_safe_config = true,
+ .flags = HW_CLK_CTRL_MODE,
.clkr.hw.init = &(struct clk_init_data){
.name = "video_cc_mvs0_clk_src",
.parent_names = video_cc_parent_names_1,
@@ -325,6 +328,7 @@ static struct clk_rcg2 video_cc_mvs1_clk_src = {
.parent_map = video_cc_parent_map_2,
.freq_tbl = ftbl_video_cc_mvs1_clk_src,
.enable_safe_config = true,
+ .flags = HW_CLK_CTRL_MODE,
.clkr.hw.init = &(struct clk_init_data){
.name = "video_cc_mvs1_clk_src",
.parent_names = video_cc_parent_names_2,
diff --git a/drivers/clk/sprd/sc9860-clk.c b/drivers/clk/sprd/sc9860-clk.c
index 9980ab5..f76305b 100644
--- a/drivers/clk/sprd/sc9860-clk.c
+++ b/drivers/clk/sprd/sc9860-clk.c
@@ -2023,6 +2023,7 @@ static int sc9860_clk_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
const struct sprd_clk_desc *desc;
+ int ret;
match = of_match_node(sprd_sc9860_clk_ids, pdev->dev.of_node);
if (!match) {
@@ -2031,7 +2032,9 @@ static int sc9860_clk_probe(struct platform_device *pdev)
}
desc = match->data;
- sprd_clk_regmap_init(pdev, desc);
+ ret = sprd_clk_regmap_init(pdev, desc);
+ if (ret)
+ return ret;
return sprd_clk_probe(&pdev->dev, desc->hw_clks);
}
diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c
index 9eb1cb1..4e1bc23 100644
--- a/drivers/clk/tegra/clk-tegra210.c
+++ b/drivers/clk/tegra/clk-tegra210.c
@@ -2214,9 +2214,9 @@ static struct div_nmp pllu_nmp = {
};
static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
- { 12000000, 480000000, 40, 1, 0, 0 },
- { 13000000, 480000000, 36, 1, 0, 0 }, /* actual: 468.0 MHz */
- { 38400000, 480000000, 25, 2, 0, 0 },
+ { 12000000, 480000000, 40, 1, 1, 0 },
+ { 13000000, 480000000, 36, 1, 1, 0 }, /* actual: 468.0 MHz */
+ { 38400000, 480000000, 25, 2, 1, 0 },
{ 0, 0, 0, 0, 0, 0 },
};
@@ -3343,6 +3343,7 @@ static struct tegra_clk_init_table init_table[] __initdata = {
{ TEGRA210_CLK_DFLL_REF, TEGRA210_CLK_PLL_P, 51000000, 1 },
{ TEGRA210_CLK_SBC4, TEGRA210_CLK_PLL_P, 12000000, 1 },
{ TEGRA210_CLK_PLL_RE_VCO, TEGRA210_CLK_CLK_MAX, 672000000, 1 },
+ { TEGRA210_CLK_PLL_U_OUT1, TEGRA210_CLK_CLK_MAX, 48000000, 1 },
{ TEGRA210_CLK_XUSB_GATE, TEGRA210_CLK_CLK_MAX, 0, 1 },
{ TEGRA210_CLK_XUSB_SS_SRC, TEGRA210_CLK_PLL_U_480M, 120000000, 0 },
{ TEGRA210_CLK_XUSB_FS_SRC, TEGRA210_CLK_PLL_U_48M, 48000000, 0 },
@@ -3367,7 +3368,6 @@ static struct tegra_clk_init_table init_table[] __initdata = {
{ TEGRA210_CLK_PLL_DP, TEGRA210_CLK_CLK_MAX, 270000000, 0 },
{ TEGRA210_CLK_SOC_THERM, TEGRA210_CLK_PLL_P, 51000000, 0 },
{ TEGRA210_CLK_CCLK_G, TEGRA210_CLK_CLK_MAX, 0, 1 },
- { TEGRA210_CLK_PLL_U_OUT1, TEGRA210_CLK_CLK_MAX, 48000000, 1 },
{ TEGRA210_CLK_PLL_U_OUT2, TEGRA210_CLK_CLK_MAX, 60000000, 1 },
/* This MUST be the last entry. */
{ TEGRA210_CLK_CLK_MAX, TEGRA210_CLK_CLK_MAX, 0, 0 },
diff --git a/drivers/clk/ti/clkctrl.c b/drivers/clk/ti/clkctrl.c
index ca32183..dfaa5aa 100644
--- a/drivers/clk/ti/clkctrl.c
+++ b/drivers/clk/ti/clkctrl.c
@@ -229,6 +229,7 @@ static struct clk_hw *_ti_omap4_clkctrl_xlate(struct of_phandle_args *clkspec,
{
struct omap_clkctrl_provider *provider = data;
struct omap_clkctrl_clk *entry;
+ bool found = false;
if (clkspec->args_count != 2)
return ERR_PTR(-EINVAL);
@@ -238,11 +239,13 @@ static struct clk_hw *_ti_omap4_clkctrl_xlate(struct of_phandle_args *clkspec,
list_for_each_entry(entry, &provider->clocks, node) {
if (entry->reg_offset == clkspec->args[0] &&
- entry->bit_offset == clkspec->args[1])
+ entry->bit_offset == clkspec->args[1]) {
+ found = true;
break;
+ }
}
- if (!entry)
+ if (!found)
return ERR_PTR(-EINVAL);
return entry->clk;
diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c
index d55c30f..aaf5bfa 100644
--- a/drivers/clocksource/exynos_mct.c
+++ b/drivers/clocksource/exynos_mct.c
@@ -211,7 +211,7 @@ static void exynos4_frc_resume(struct clocksource *cs)
static struct clocksource mct_frc = {
.name = "mct-frc",
- .rating = 400,
+ .rating = 450, /* use value higher than ARM arch timer */
.read = exynos4_frc_read,
.mask = CLOCKSOURCE_MASK(32),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
@@ -466,7 +466,7 @@ static int exynos4_mct_starting_cpu(unsigned int cpu)
evt->set_state_oneshot_stopped = set_state_shutdown;
evt->tick_resume = set_state_shutdown;
evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
- evt->rating = 450;
+ evt->rating = 500; /* use value higher than ARM arch timer */
exynos4_mct_write(TICK_BASE_CNT, mevt->base + MCT_L_TCNTB_OFFSET);
diff --git a/drivers/crypto/amcc/crypto4xx_alg.c b/drivers/crypto/amcc/crypto4xx_alg.c
index 0c85a51..1d87dec 100644
--- a/drivers/crypto/amcc/crypto4xx_alg.c
+++ b/drivers/crypto/amcc/crypto4xx_alg.c
@@ -76,12 +76,16 @@ static void set_dynamic_sa_command_1(struct dynamic_sa_ctl *sa, u32 cm,
}
static inline int crypto4xx_crypt(struct skcipher_request *req,
- const unsigned int ivlen, bool decrypt)
+ const unsigned int ivlen, bool decrypt,
+ bool check_blocksize)
{
struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(req);
struct crypto4xx_ctx *ctx = crypto_skcipher_ctx(cipher);
__le32 iv[AES_IV_SIZE];
+ if (check_blocksize && !IS_ALIGNED(req->cryptlen, AES_BLOCK_SIZE))
+ return -EINVAL;
+
if (ivlen)
crypto4xx_memcpy_to_le32(iv, req->iv, ivlen);
@@ -90,24 +94,34 @@ static inline int crypto4xx_crypt(struct skcipher_request *req,
ctx->sa_len, 0, NULL);
}
-int crypto4xx_encrypt_noiv(struct skcipher_request *req)
+int crypto4xx_encrypt_noiv_block(struct skcipher_request *req)
{
- return crypto4xx_crypt(req, 0, false);
+ return crypto4xx_crypt(req, 0, false, true);
}
-int crypto4xx_encrypt_iv(struct skcipher_request *req)
+int crypto4xx_encrypt_iv_stream(struct skcipher_request *req)
{
- return crypto4xx_crypt(req, AES_IV_SIZE, false);
+ return crypto4xx_crypt(req, AES_IV_SIZE, false, false);
}
-int crypto4xx_decrypt_noiv(struct skcipher_request *req)
+int crypto4xx_decrypt_noiv_block(struct skcipher_request *req)
{
- return crypto4xx_crypt(req, 0, true);
+ return crypto4xx_crypt(req, 0, true, true);
}
-int crypto4xx_decrypt_iv(struct skcipher_request *req)
+int crypto4xx_decrypt_iv_stream(struct skcipher_request *req)
{
- return crypto4xx_crypt(req, AES_IV_SIZE, true);
+ return crypto4xx_crypt(req, AES_IV_SIZE, true, false);
+}
+
+int crypto4xx_encrypt_iv_block(struct skcipher_request *req)
+{
+ return crypto4xx_crypt(req, AES_IV_SIZE, false, true);
+}
+
+int crypto4xx_decrypt_iv_block(struct skcipher_request *req)
+{
+ return crypto4xx_crypt(req, AES_IV_SIZE, true, true);
}
/**
@@ -278,8 +292,8 @@ crypto4xx_ctr_crypt(struct skcipher_request *req, bool encrypt)
return ret;
}
- return encrypt ? crypto4xx_encrypt_iv(req)
- : crypto4xx_decrypt_iv(req);
+ return encrypt ? crypto4xx_encrypt_iv_stream(req)
+ : crypto4xx_decrypt_iv_stream(req);
}
static int crypto4xx_sk_setup_fallback(struct crypto4xx_ctx *ctx,
diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
index d2ec9fd..6386e17 100644
--- a/drivers/crypto/amcc/crypto4xx_core.c
+++ b/drivers/crypto/amcc/crypto4xx_core.c
@@ -1153,8 +1153,8 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = {
.max_keysize = AES_MAX_KEY_SIZE,
.ivsize = AES_IV_SIZE,
.setkey = crypto4xx_setkey_aes_cbc,
- .encrypt = crypto4xx_encrypt_iv,
- .decrypt = crypto4xx_decrypt_iv,
+ .encrypt = crypto4xx_encrypt_iv_block,
+ .decrypt = crypto4xx_decrypt_iv_block,
.init = crypto4xx_sk_init,
.exit = crypto4xx_sk_exit,
} },
@@ -1173,8 +1173,8 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = {
.max_keysize = AES_MAX_KEY_SIZE,
.ivsize = AES_IV_SIZE,
.setkey = crypto4xx_setkey_aes_cfb,
- .encrypt = crypto4xx_encrypt_iv,
- .decrypt = crypto4xx_decrypt_iv,
+ .encrypt = crypto4xx_encrypt_iv_stream,
+ .decrypt = crypto4xx_decrypt_iv_stream,
.init = crypto4xx_sk_init,
.exit = crypto4xx_sk_exit,
} },
@@ -1186,7 +1186,7 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = {
.cra_flags = CRYPTO_ALG_NEED_FALLBACK |
CRYPTO_ALG_ASYNC |
CRYPTO_ALG_KERN_DRIVER_ONLY,
- .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_blocksize = 1,
.cra_ctxsize = sizeof(struct crypto4xx_ctx),
.cra_module = THIS_MODULE,
},
@@ -1206,7 +1206,7 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = {
.cra_priority = CRYPTO4XX_CRYPTO_PRIORITY,
.cra_flags = CRYPTO_ALG_ASYNC |
CRYPTO_ALG_KERN_DRIVER_ONLY,
- .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_blocksize = 1,
.cra_ctxsize = sizeof(struct crypto4xx_ctx),
.cra_module = THIS_MODULE,
},
@@ -1226,15 +1226,15 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = {
.cra_priority = CRYPTO4XX_CRYPTO_PRIORITY,
.cra_flags = CRYPTO_ALG_ASYNC |
CRYPTO_ALG_KERN_DRIVER_ONLY,
- .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_blocksize = 1,
.cra_ctxsize = sizeof(struct crypto4xx_ctx),
.cra_module = THIS_MODULE,
},
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
.setkey = crypto4xx_setkey_aes_ecb,
- .encrypt = crypto4xx_encrypt_noiv,
- .decrypt = crypto4xx_decrypt_noiv,
+ .encrypt = crypto4xx_encrypt_noiv_block,
+ .decrypt = crypto4xx_decrypt_noiv_block,
.init = crypto4xx_sk_init,
.exit = crypto4xx_sk_exit,
} },
@@ -1245,7 +1245,7 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = {
.cra_priority = CRYPTO4XX_CRYPTO_PRIORITY,
.cra_flags = CRYPTO_ALG_ASYNC |
CRYPTO_ALG_KERN_DRIVER_ONLY,
- .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_blocksize = 1,
.cra_ctxsize = sizeof(struct crypto4xx_ctx),
.cra_module = THIS_MODULE,
},
@@ -1253,8 +1253,8 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = {
.max_keysize = AES_MAX_KEY_SIZE,
.ivsize = AES_IV_SIZE,
.setkey = crypto4xx_setkey_aes_ofb,
- .encrypt = crypto4xx_encrypt_iv,
- .decrypt = crypto4xx_decrypt_iv,
+ .encrypt = crypto4xx_encrypt_iv_stream,
+ .decrypt = crypto4xx_decrypt_iv_stream,
.init = crypto4xx_sk_init,
.exit = crypto4xx_sk_exit,
} },
diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h
index e2ca567..21a6bbc 100644
--- a/drivers/crypto/amcc/crypto4xx_core.h
+++ b/drivers/crypto/amcc/crypto4xx_core.h
@@ -179,10 +179,12 @@ int crypto4xx_setkey_rfc3686(struct crypto_skcipher *cipher,
const u8 *key, unsigned int keylen);
int crypto4xx_encrypt_ctr(struct skcipher_request *req);
int crypto4xx_decrypt_ctr(struct skcipher_request *req);
-int crypto4xx_encrypt_iv(struct skcipher_request *req);
-int crypto4xx_decrypt_iv(struct skcipher_request *req);
-int crypto4xx_encrypt_noiv(struct skcipher_request *req);
-int crypto4xx_decrypt_noiv(struct skcipher_request *req);
+int crypto4xx_encrypt_iv_stream(struct skcipher_request *req);
+int crypto4xx_decrypt_iv_stream(struct skcipher_request *req);
+int crypto4xx_encrypt_iv_block(struct skcipher_request *req);
+int crypto4xx_decrypt_iv_block(struct skcipher_request *req);
+int crypto4xx_encrypt_noiv_block(struct skcipher_request *req);
+int crypto4xx_decrypt_noiv_block(struct skcipher_request *req);
int crypto4xx_rfc3686_encrypt(struct skcipher_request *req);
int crypto4xx_rfc3686_decrypt(struct skcipher_request *req);
int crypto4xx_sha1_alg_init(struct crypto_tfm *tfm);
diff --git a/drivers/crypto/amcc/crypto4xx_trng.c b/drivers/crypto/amcc/crypto4xx_trng.c
index 53ab1f1..8a3ed40 100644
--- a/drivers/crypto/amcc/crypto4xx_trng.c
+++ b/drivers/crypto/amcc/crypto4xx_trng.c
@@ -111,7 +111,6 @@ void ppc4xx_trng_probe(struct crypto4xx_core_device *core_dev)
return;
err_out:
- of_node_put(trng);
iounmap(dev->trng_base);
kfree(rng);
dev->trng_base = NULL;
diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
index 9bc54c3..1907945 100644
--- a/drivers/crypto/caam/caamalg.c
+++ b/drivers/crypto/caam/caamalg.c
@@ -887,6 +887,7 @@ static void ablkcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err,
struct ablkcipher_request *req = context;
struct ablkcipher_edesc *edesc;
struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
+ struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher);
int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
#ifdef DEBUG
@@ -911,10 +912,11 @@ static void ablkcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err,
/*
* The crypto API expects us to set the IV (req->info) to the last
- * ciphertext block. This is used e.g. by the CTS mode.
+ * ciphertext block when running in CBC mode.
*/
- scatterwalk_map_and_copy(req->info, req->dst, req->nbytes - ivsize,
- ivsize, 0);
+ if ((ctx->cdata.algtype & OP_ALG_AAI_MASK) == OP_ALG_AAI_CBC)
+ scatterwalk_map_and_copy(req->info, req->dst, req->nbytes -
+ ivsize, ivsize, 0);
/* In case initial IV was generated, copy it in GIVCIPHER request */
if (edesc->iv_dir == DMA_FROM_DEVICE) {
@@ -1651,10 +1653,11 @@ static int ablkcipher_decrypt(struct ablkcipher_request *req)
/*
* The crypto API expects us to set the IV (req->info) to the last
- * ciphertext block.
+ * ciphertext block when running in CBC mode.
*/
- scatterwalk_map_and_copy(req->info, req->src, req->nbytes - ivsize,
- ivsize, 0);
+ if ((ctx->cdata.algtype & OP_ALG_AAI_MASK) == OP_ALG_AAI_CBC)
+ scatterwalk_map_and_copy(req->info, req->src, req->nbytes -
+ ivsize, ivsize, 0);
/* Create and submit job descriptor*/
init_ablkcipher_job(ctx->sh_desc_dec, ctx->sh_desc_dec_dma, edesc, req);
diff --git a/drivers/crypto/ccp/ccp-dev.c b/drivers/crypto/ccp/ccp-dev.c
index 1b5035d..9b6d897 100644
--- a/drivers/crypto/ccp/ccp-dev.c
+++ b/drivers/crypto/ccp/ccp-dev.c
@@ -35,56 +35,62 @@ struct ccp_tasklet_data {
};
/* Human-readable error strings */
+#define CCP_MAX_ERROR_CODE 64
static char *ccp_error_codes[] = {
"",
- "ERR 01: ILLEGAL_ENGINE",
- "ERR 02: ILLEGAL_KEY_ID",
- "ERR 03: ILLEGAL_FUNCTION_TYPE",
- "ERR 04: ILLEGAL_FUNCTION_MODE",
- "ERR 05: ILLEGAL_FUNCTION_ENCRYPT",
- "ERR 06: ILLEGAL_FUNCTION_SIZE",
- "ERR 07: Zlib_MISSING_INIT_EOM",
- "ERR 08: ILLEGAL_FUNCTION_RSVD",
- "ERR 09: ILLEGAL_BUFFER_LENGTH",
- "ERR 10: VLSB_FAULT",
- "ERR 11: ILLEGAL_MEM_ADDR",
- "ERR 12: ILLEGAL_MEM_SEL",
- "ERR 13: ILLEGAL_CONTEXT_ID",
- "ERR 14: ILLEGAL_KEY_ADDR",
- "ERR 15: 0xF Reserved",
- "ERR 16: Zlib_ILLEGAL_MULTI_QUEUE",
- "ERR 17: Zlib_ILLEGAL_JOBID_CHANGE",
- "ERR 18: CMD_TIMEOUT",
- "ERR 19: IDMA0_AXI_SLVERR",
- "ERR 20: IDMA0_AXI_DECERR",
- "ERR 21: 0x15 Reserved",
- "ERR 22: IDMA1_AXI_SLAVE_FAULT",
- "ERR 23: IDMA1_AIXI_DECERR",
- "ERR 24: 0x18 Reserved",
- "ERR 25: ZLIBVHB_AXI_SLVERR",
- "ERR 26: ZLIBVHB_AXI_DECERR",
- "ERR 27: 0x1B Reserved",
- "ERR 27: ZLIB_UNEXPECTED_EOM",
- "ERR 27: ZLIB_EXTRA_DATA",
- "ERR 30: ZLIB_BTYPE",
- "ERR 31: ZLIB_UNDEFINED_SYMBOL",
- "ERR 32: ZLIB_UNDEFINED_DISTANCE_S",
- "ERR 33: ZLIB_CODE_LENGTH_SYMBOL",
- "ERR 34: ZLIB _VHB_ILLEGAL_FETCH",
- "ERR 35: ZLIB_UNCOMPRESSED_LEN",
- "ERR 36: ZLIB_LIMIT_REACHED",
- "ERR 37: ZLIB_CHECKSUM_MISMATCH0",
- "ERR 38: ODMA0_AXI_SLVERR",
- "ERR 39: ODMA0_AXI_DECERR",
- "ERR 40: 0x28 Reserved",
- "ERR 41: ODMA1_AXI_SLVERR",
- "ERR 42: ODMA1_AXI_DECERR",
- "ERR 43: LSB_PARITY_ERR",
+ "ILLEGAL_ENGINE",
+ "ILLEGAL_KEY_ID",
+ "ILLEGAL_FUNCTION_TYPE",
+ "ILLEGAL_FUNCTION_MODE",
+ "ILLEGAL_FUNCTION_ENCRYPT",
+ "ILLEGAL_FUNCTION_SIZE",
+ "Zlib_MISSING_INIT_EOM",
+ "ILLEGAL_FUNCTION_RSVD",
+ "ILLEGAL_BUFFER_LENGTH",
+ "VLSB_FAULT",
+ "ILLEGAL_MEM_ADDR",
+ "ILLEGAL_MEM_SEL",
+ "ILLEGAL_CONTEXT_ID",
+ "ILLEGAL_KEY_ADDR",
+ "0xF Reserved",
+ "Zlib_ILLEGAL_MULTI_QUEUE",
+ "Zlib_ILLEGAL_JOBID_CHANGE",
+ "CMD_TIMEOUT",
+ "IDMA0_AXI_SLVERR",
+ "IDMA0_AXI_DECERR",
+ "0x15 Reserved",
+ "IDMA1_AXI_SLAVE_FAULT",
+ "IDMA1_AIXI_DECERR",
+ "0x18 Reserved",
+ "ZLIBVHB_AXI_SLVERR",
+ "ZLIBVHB_AXI_DECERR",
+ "0x1B Reserved",
+ "ZLIB_UNEXPECTED_EOM",
+ "ZLIB_EXTRA_DATA",
+ "ZLIB_BTYPE",
+ "ZLIB_UNDEFINED_SYMBOL",
+ "ZLIB_UNDEFINED_DISTANCE_S",
+ "ZLIB_CODE_LENGTH_SYMBOL",
+ "ZLIB _VHB_ILLEGAL_FETCH",
+ "ZLIB_UNCOMPRESSED_LEN",
+ "ZLIB_LIMIT_REACHED",
+ "ZLIB_CHECKSUM_MISMATCH0",
+ "ODMA0_AXI_SLVERR",
+ "ODMA0_AXI_DECERR",
+ "0x28 Reserved",
+ "ODMA1_AXI_SLVERR",
+ "ODMA1_AXI_DECERR",
};
-void ccp_log_error(struct ccp_device *d, int e)
+void ccp_log_error(struct ccp_device *d, unsigned int e)
{
- dev_err(d->dev, "CCP error: %s (0x%x)\n", ccp_error_codes[e], e);
+ if (WARN_ON(e >= CCP_MAX_ERROR_CODE))
+ return;
+
+ if (e < ARRAY_SIZE(ccp_error_codes))
+ dev_err(d->dev, "CCP error %d: %s\n", e, ccp_error_codes[e]);
+ else
+ dev_err(d->dev, "CCP error %d: Unknown Error\n", e);
}
/* List of CCPs, CCP count, read-write access lock, and access functions
diff --git a/drivers/crypto/ccp/ccp-dev.h b/drivers/crypto/ccp/ccp-dev.h
index 6810b65..7442b04 100644
--- a/drivers/crypto/ccp/ccp-dev.h
+++ b/drivers/crypto/ccp/ccp-dev.h
@@ -632,7 +632,7 @@ struct ccp5_desc {
void ccp_add_device(struct ccp_device *ccp);
void ccp_del_device(struct ccp_device *ccp);
-extern void ccp_log_error(struct ccp_device *, int);
+extern void ccp_log_error(struct ccp_device *, unsigned int);
struct ccp_device *ccp_alloc_struct(struct sp_device *sp);
bool ccp_queues_suspended(struct ccp_device *ccp);
diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c
index 0ea43cd..e212bad 100644
--- a/drivers/crypto/ccp/ccp-ops.c
+++ b/drivers/crypto/ccp/ccp-ops.c
@@ -625,6 +625,7 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q,
unsigned long long *final;
unsigned int dm_offset;
+ unsigned int jobid;
unsigned int ilen;
bool in_place = true; /* Default value */
int ret;
@@ -663,9 +664,11 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q,
p_tag = scatterwalk_ffwd(sg_tag, p_inp, ilen);
}
+ jobid = CCP_NEW_JOBID(cmd_q->ccp);
+
memset(&op, 0, sizeof(op));
op.cmd_q = cmd_q;
- op.jobid = CCP_NEW_JOBID(cmd_q->ccp);
+ op.jobid = jobid;
op.sb_key = cmd_q->sb_key; /* Pre-allocated */
op.sb_ctx = cmd_q->sb_ctx; /* Pre-allocated */
op.init = 1;
@@ -816,6 +819,13 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q,
final[0] = cpu_to_be64(aes->aad_len * 8);
final[1] = cpu_to_be64(ilen * 8);
+ memset(&op, 0, sizeof(op));
+ op.cmd_q = cmd_q;
+ op.jobid = jobid;
+ op.sb_key = cmd_q->sb_key; /* Pre-allocated */
+ op.sb_ctx = cmd_q->sb_ctx; /* Pre-allocated */
+ op.init = 1;
+ op.u.aes.type = aes->type;
op.u.aes.mode = CCP_AES_MODE_GHASH;
op.u.aes.action = CCP_AES_GHASHFINAL;
op.src.type = CCP_MEMTYPE_SYSTEM;
@@ -843,7 +853,8 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q,
if (ret)
goto e_tag;
- ret = memcmp(tag.address, final_wa.address, AES_BLOCK_SIZE);
+ ret = crypto_memneq(tag.address, final_wa.address,
+ AES_BLOCK_SIZE) ? -EBADMSG : 0;
ccp_dm_free(&tag);
}
diff --git a/drivers/crypto/inside-secure/safexcel_cipher.c b/drivers/crypto/inside-secure/safexcel_cipher.c
index 3aef1d4..42a3830 100644
--- a/drivers/crypto/inside-secure/safexcel_cipher.c
+++ b/drivers/crypto/inside-secure/safexcel_cipher.c
@@ -51,6 +51,8 @@ struct safexcel_cipher_ctx {
struct safexcel_cipher_req {
enum safexcel_cipher_direction direction;
+ /* Number of result descriptors associated to the request */
+ unsigned int rdescs;
bool needs_inv;
};
@@ -333,7 +335,10 @@ static int safexcel_handle_req_result(struct safexcel_crypto_priv *priv, int rin
*ret = 0;
- do {
+ if (unlikely(!sreq->rdescs))
+ return 0;
+
+ while (sreq->rdescs--) {
rdesc = safexcel_ring_next_rptr(priv, &priv->ring[ring].rdr);
if (IS_ERR(rdesc)) {
dev_err(priv->dev,
@@ -346,7 +351,7 @@ static int safexcel_handle_req_result(struct safexcel_crypto_priv *priv, int rin
*ret = safexcel_rdesc_check_errors(priv, rdesc);
ndesc++;
- } while (!rdesc->last_seg);
+ }
safexcel_complete(priv, ring);
@@ -501,6 +506,7 @@ static int safexcel_send_req(struct crypto_async_request *base, int ring,
static int safexcel_handle_inv_result(struct safexcel_crypto_priv *priv,
int ring,
struct crypto_async_request *base,
+ struct safexcel_cipher_req *sreq,
bool *should_complete, int *ret)
{
struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(base->tfm);
@@ -509,7 +515,10 @@ static int safexcel_handle_inv_result(struct safexcel_crypto_priv *priv,
*ret = 0;
- do {
+ if (unlikely(!sreq->rdescs))
+ return 0;
+
+ while (sreq->rdescs--) {
rdesc = safexcel_ring_next_rptr(priv, &priv->ring[ring].rdr);
if (IS_ERR(rdesc)) {
dev_err(priv->dev,
@@ -522,7 +531,7 @@ static int safexcel_handle_inv_result(struct safexcel_crypto_priv *priv,
*ret = safexcel_rdesc_check_errors(priv, rdesc);
ndesc++;
- } while (!rdesc->last_seg);
+ }
safexcel_complete(priv, ring);
@@ -564,7 +573,7 @@ static int safexcel_skcipher_handle_result(struct safexcel_crypto_priv *priv,
if (sreq->needs_inv) {
sreq->needs_inv = false;
- err = safexcel_handle_inv_result(priv, ring, async,
+ err = safexcel_handle_inv_result(priv, ring, async, sreq,
should_complete, ret);
} else {
err = safexcel_handle_req_result(priv, ring, async, req->src,
@@ -587,7 +596,7 @@ static int safexcel_aead_handle_result(struct safexcel_crypto_priv *priv,
if (sreq->needs_inv) {
sreq->needs_inv = false;
- err = safexcel_handle_inv_result(priv, ring, async,
+ err = safexcel_handle_inv_result(priv, ring, async, sreq,
should_complete, ret);
} else {
err = safexcel_handle_req_result(priv, ring, async, req->src,
@@ -633,6 +642,8 @@ static int safexcel_skcipher_send(struct crypto_async_request *async, int ring,
ret = safexcel_send_req(async, ring, sreq, req->src,
req->dst, req->cryptlen, 0, 0, req->iv,
commands, results);
+
+ sreq->rdescs = *results;
return ret;
}
@@ -655,6 +666,7 @@ static int safexcel_aead_send(struct crypto_async_request *async, int ring,
req->cryptlen, req->assoclen,
crypto_aead_authsize(tfm), req->iv,
commands, results);
+ sreq->rdescs = *results;
return ret;
}
diff --git a/drivers/crypto/nx/nx-842-powernv.c b/drivers/crypto/nx/nx-842-powernv.c
index c68df7e..7ce2467 100644
--- a/drivers/crypto/nx/nx-842-powernv.c
+++ b/drivers/crypto/nx/nx-842-powernv.c
@@ -36,8 +36,6 @@ MODULE_ALIAS_CRYPTO("842-nx");
#define WORKMEM_ALIGN (CRB_ALIGN)
#define CSB_WAIT_MAX (5000) /* ms */
#define VAS_RETRIES (10)
-/* # of requests allowed per RxFIFO at a time. 0 for unlimited */
-#define MAX_CREDITS_PER_RXFIFO (1024)
struct nx842_workmem {
/* Below fields must be properly aligned */
@@ -821,7 +819,11 @@ static int __init vas_cfg_coproc_info(struct device_node *dn, int chip_id,
rxattr.lnotify_lpid = lpid;
rxattr.lnotify_pid = pid;
rxattr.lnotify_tid = tid;
- rxattr.wcreds_max = MAX_CREDITS_PER_RXFIFO;
+ /*
+ * Maximum RX window credits can not be more than #CRBs in
+ * RxFIFO. Otherwise, can get checkstop if RxFIFO overruns.
+ */
+ rxattr.wcreds_max = fifo_size / CRB_SIZE;
/*
* Open a VAS receice window which is used to configure RxFIFO
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index f4f3e9a..41b288b 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -334,6 +334,21 @@ int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc,
}
EXPORT_SYMBOL(talitos_submit);
+static __be32 get_request_hdr(struct talitos_request *request, bool is_sec1)
+{
+ struct talitos_edesc *edesc;
+
+ if (!is_sec1)
+ return request->desc->hdr;
+
+ if (!request->desc->next_desc)
+ return request->desc->hdr1;
+
+ edesc = container_of(request->desc, struct talitos_edesc, desc);
+
+ return ((struct talitos_desc *)(edesc->buf + edesc->dma_len))->hdr1;
+}
+
/*
* process what was done, notify callback of error if not
*/
@@ -355,12 +370,7 @@ static void flush_channel(struct device *dev, int ch, int error, int reset_ch)
/* descriptors with their done bits set don't get the error */
rmb();
- if (!is_sec1)
- hdr = request->desc->hdr;
- else if (request->desc->next_desc)
- hdr = (request->desc + 1)->hdr1;
- else
- hdr = request->desc->hdr1;
+ hdr = get_request_hdr(request, is_sec1);
if ((hdr & DESC_HDR_DONE) == DESC_HDR_DONE)
status = 0;
@@ -490,8 +500,14 @@ static u32 current_desc_hdr(struct device *dev, int ch)
}
}
- if (priv->chan[ch].fifo[iter].desc->next_desc == cur_desc)
- return (priv->chan[ch].fifo[iter].desc + 1)->hdr;
+ if (priv->chan[ch].fifo[iter].desc->next_desc == cur_desc) {
+ struct talitos_edesc *edesc;
+
+ edesc = container_of(priv->chan[ch].fifo[iter].desc,
+ struct talitos_edesc, desc);
+ return ((struct talitos_desc *)
+ (edesc->buf + edesc->dma_len))->hdr;
+ }
return priv->chan[ch].fifo[iter].desc->hdr;
}
@@ -913,36 +929,6 @@ static int aead_setkey(struct crypto_aead *authenc,
return -EINVAL;
}
-/*
- * talitos_edesc - s/w-extended descriptor
- * @src_nents: number of segments in input scatterlist
- * @dst_nents: number of segments in output scatterlist
- * @icv_ool: whether ICV is out-of-line
- * @iv_dma: dma address of iv for checking continuity and link table
- * @dma_len: length of dma mapped link_tbl space
- * @dma_link_tbl: bus physical address of link_tbl/buf
- * @desc: h/w descriptor
- * @link_tbl: input and output h/w link tables (if {src,dst}_nents > 1) (SEC2)
- * @buf: input and output buffeur (if {src,dst}_nents > 1) (SEC1)
- *
- * if decrypting (with authcheck), or either one of src_nents or dst_nents
- * is greater than 1, an integrity check value is concatenated to the end
- * of link_tbl data
- */
-struct talitos_edesc {
- int src_nents;
- int dst_nents;
- bool icv_ool;
- dma_addr_t iv_dma;
- int dma_len;
- dma_addr_t dma_link_tbl;
- struct talitos_desc desc;
- union {
- struct talitos_ptr link_tbl[0];
- u8 buf[0];
- };
-};
-
static void talitos_sg_unmap(struct device *dev,
struct talitos_edesc *edesc,
struct scatterlist *src,
@@ -1015,7 +1001,6 @@ static void ipsec_esp_encrypt_done(struct device *dev,
unsigned int authsize = crypto_aead_authsize(authenc);
unsigned int ivsize = crypto_aead_ivsize(authenc);
struct talitos_edesc *edesc;
- struct scatterlist *sg;
void *icvdata;
edesc = container_of(desc, struct talitos_edesc, desc);
@@ -1029,9 +1014,8 @@ static void ipsec_esp_encrypt_done(struct device *dev,
else
icvdata = &edesc->link_tbl[edesc->src_nents +
edesc->dst_nents + 2];
- sg = sg_last(areq->dst, edesc->dst_nents);
- memcpy((char *)sg_virt(sg) + sg->length - authsize,
- icvdata, authsize);
+ sg_pcopy_from_buffer(areq->dst, edesc->dst_nents ? : 1, icvdata,
+ authsize, areq->assoclen + areq->cryptlen);
}
dma_unmap_single(dev, edesc->iv_dma, ivsize, DMA_TO_DEVICE);
@@ -1049,7 +1033,6 @@ static void ipsec_esp_decrypt_swauth_done(struct device *dev,
struct crypto_aead *authenc = crypto_aead_reqtfm(req);
unsigned int authsize = crypto_aead_authsize(authenc);
struct talitos_edesc *edesc;
- struct scatterlist *sg;
char *oicv, *icv;
struct talitos_private *priv = dev_get_drvdata(dev);
bool is_sec1 = has_ftr_sec1(priv);
@@ -1059,9 +1042,18 @@ static void ipsec_esp_decrypt_swauth_done(struct device *dev,
ipsec_esp_unmap(dev, edesc, req);
if (!err) {
+ char icvdata[SHA512_DIGEST_SIZE];
+ int nents = edesc->dst_nents ? : 1;
+ unsigned int len = req->assoclen + req->cryptlen;
+
/* auth check */
- sg = sg_last(req->dst, edesc->dst_nents ? : 1);
- icv = (char *)sg_virt(sg) + sg->length - authsize;
+ if (nents > 1) {
+ sg_pcopy_to_buffer(req->dst, nents, icvdata, authsize,
+ len - authsize);
+ icv = icvdata;
+ } else {
+ icv = (char *)sg_virt(req->dst) + len - authsize;
+ }
if (edesc->dma_len) {
if (is_sec1)
@@ -1431,15 +1423,11 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev,
edesc->dst_nents = dst_nents;
edesc->iv_dma = iv_dma;
edesc->dma_len = dma_len;
- if (dma_len) {
- void *addr = &edesc->link_tbl[0];
-
- if (is_sec1 && !dst)
- addr += sizeof(struct talitos_desc);
- edesc->dma_link_tbl = dma_map_single(dev, addr,
+ if (dma_len)
+ edesc->dma_link_tbl = dma_map_single(dev, &edesc->link_tbl[0],
edesc->dma_len,
DMA_BIDIRECTIONAL);
- }
+
return edesc;
}
@@ -1481,7 +1469,6 @@ static int aead_decrypt(struct aead_request *req)
struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
struct talitos_private *priv = dev_get_drvdata(ctx->dev);
struct talitos_edesc *edesc;
- struct scatterlist *sg;
void *icvdata;
req->cryptlen -= authsize;
@@ -1515,9 +1502,8 @@ static int aead_decrypt(struct aead_request *req)
else
icvdata = &edesc->link_tbl[0];
- sg = sg_last(req->src, edesc->src_nents ? : 1);
-
- memcpy(icvdata, (char *)sg_virt(sg) + sg->length - authsize, authsize);
+ sg_pcopy_to_buffer(req->src, edesc->src_nents ? : 1, icvdata, authsize,
+ req->assoclen + req->cryptlen - authsize);
return ipsec_esp(edesc, req, ipsec_esp_decrypt_swauth_done);
}
@@ -1571,11 +1557,15 @@ static void ablkcipher_done(struct device *dev,
int err)
{
struct ablkcipher_request *areq = context;
+ struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
+ struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+ unsigned int ivsize = crypto_ablkcipher_ivsize(cipher);
struct talitos_edesc *edesc;
edesc = container_of(desc, struct talitos_edesc, desc);
common_nonsnoop_unmap(dev, edesc, areq);
+ memcpy(areq->info, ctx->iv, ivsize);
kfree(edesc);
@@ -1706,14 +1696,16 @@ static void common_nonsnoop_hash_unmap(struct device *dev,
struct talitos_private *priv = dev_get_drvdata(dev);
bool is_sec1 = has_ftr_sec1(priv);
struct talitos_desc *desc = &edesc->desc;
- struct talitos_desc *desc2 = desc + 1;
+ struct talitos_desc *desc2 = (struct talitos_desc *)
+ (edesc->buf + edesc->dma_len);
unmap_single_talitos_ptr(dev, &edesc->desc.ptr[5], DMA_FROM_DEVICE);
if (desc->next_desc &&
desc->ptr[5].ptr != desc2->ptr[5].ptr)
unmap_single_talitos_ptr(dev, &desc2->ptr[5], DMA_FROM_DEVICE);
- talitos_sg_unmap(dev, edesc, req_ctx->psrc, NULL, 0, 0);
+ if (req_ctx->psrc)
+ talitos_sg_unmap(dev, edesc, req_ctx->psrc, NULL, 0, 0);
/* When using hashctx-in, must unmap it. */
if (from_talitos_ptr_len(&edesc->desc.ptr[1], is_sec1))
@@ -1780,7 +1772,6 @@ static void talitos_handle_buggy_hash(struct talitos_ctx *ctx,
static int common_nonsnoop_hash(struct talitos_edesc *edesc,
struct ahash_request *areq, unsigned int length,
- unsigned int offset,
void (*callback) (struct device *dev,
struct talitos_desc *desc,
void *context, int error))
@@ -1819,9 +1810,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
sg_count = edesc->src_nents ?: 1;
if (is_sec1 && sg_count > 1)
- sg_pcopy_to_buffer(req_ctx->psrc, sg_count,
- edesc->buf + sizeof(struct talitos_desc),
- length, req_ctx->nbuf);
+ sg_copy_to_buffer(req_ctx->psrc, sg_count, edesc->buf, length);
else if (length)
sg_count = dma_map_sg(dev, req_ctx->psrc, sg_count,
DMA_TO_DEVICE);
@@ -1834,7 +1823,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
DMA_TO_DEVICE);
} else {
sg_count = talitos_sg_map(dev, req_ctx->psrc, length, edesc,
- &desc->ptr[3], sg_count, offset, 0);
+ &desc->ptr[3], sg_count, 0, 0);
if (sg_count > 1)
sync_needed = true;
}
@@ -1858,7 +1847,8 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
talitos_handle_buggy_hash(ctx, edesc, &desc->ptr[3]);
if (is_sec1 && req_ctx->nbuf && length) {
- struct talitos_desc *desc2 = desc + 1;
+ struct talitos_desc *desc2 = (struct talitos_desc *)
+ (edesc->buf + edesc->dma_len);
dma_addr_t next_desc;
memset(desc2, 0, sizeof(*desc2));
@@ -1879,7 +1869,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
DMA_TO_DEVICE);
copy_talitos_ptr(&desc2->ptr[2], &desc->ptr[2], is_sec1);
sg_count = talitos_sg_map(dev, req_ctx->psrc, length, edesc,
- &desc2->ptr[3], sg_count, offset, 0);
+ &desc2->ptr[3], sg_count, 0, 0);
if (sg_count > 1)
sync_needed = true;
copy_talitos_ptr(&desc2->ptr[5], &desc->ptr[5], is_sec1);
@@ -1990,7 +1980,6 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
struct device *dev = ctx->dev;
struct talitos_private *priv = dev_get_drvdata(dev);
bool is_sec1 = has_ftr_sec1(priv);
- int offset = 0;
u8 *ctx_buf = req_ctx->buf[req_ctx->buf_idx];
if (!req_ctx->last && (nbytes + req_ctx->nbuf <= blocksize)) {
@@ -2030,6 +2019,8 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
sg_chain(req_ctx->bufsl, 2, areq->src);
req_ctx->psrc = req_ctx->bufsl;
} else if (is_sec1 && req_ctx->nbuf && req_ctx->nbuf < blocksize) {
+ int offset;
+
if (nbytes_to_hash > blocksize)
offset = blocksize - req_ctx->nbuf;
else
@@ -2042,7 +2033,8 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
sg_copy_to_buffer(areq->src, nents,
ctx_buf + req_ctx->nbuf, offset);
req_ctx->nbuf += offset;
- req_ctx->psrc = areq->src;
+ req_ctx->psrc = scatterwalk_ffwd(req_ctx->bufsl, areq->src,
+ offset);
} else
req_ctx->psrc = areq->src;
@@ -2082,8 +2074,7 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
if (ctx->keylen && (req_ctx->first || req_ctx->last))
edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_HMAC;
- return common_nonsnoop_hash(edesc, areq, nbytes_to_hash, offset,
- ahash_done);
+ return common_nonsnoop_hash(edesc, areq, nbytes_to_hash, ahash_done);
}
static int ahash_update(struct ahash_request *areq)
@@ -2286,7 +2277,7 @@ static struct talitos_alg_template driver_algs[] = {
.base = {
.cra_name = "authenc(hmac(sha1),cbc(aes))",
.cra_driver_name = "authenc-hmac-sha1-"
- "cbc-aes-talitos",
+ "cbc-aes-talitos-hsna",
.cra_blocksize = AES_BLOCK_SIZE,
.cra_flags = CRYPTO_ALG_ASYNC,
},
@@ -2330,7 +2321,7 @@ static struct talitos_alg_template driver_algs[] = {
.cra_name = "authenc(hmac(sha1),"
"cbc(des3_ede))",
.cra_driver_name = "authenc-hmac-sha1-"
- "cbc-3des-talitos",
+ "cbc-3des-talitos-hsna",
.cra_blocksize = DES3_EDE_BLOCK_SIZE,
.cra_flags = CRYPTO_ALG_ASYNC,
},
@@ -2372,7 +2363,7 @@ static struct talitos_alg_template driver_algs[] = {
.base = {
.cra_name = "authenc(hmac(sha224),cbc(aes))",
.cra_driver_name = "authenc-hmac-sha224-"
- "cbc-aes-talitos",
+ "cbc-aes-talitos-hsna",
.cra_blocksize = AES_BLOCK_SIZE,
.cra_flags = CRYPTO_ALG_ASYNC,
},
@@ -2416,7 +2407,7 @@ static struct talitos_alg_template driver_algs[] = {
.cra_name = "authenc(hmac(sha224),"
"cbc(des3_ede))",
.cra_driver_name = "authenc-hmac-sha224-"
- "cbc-3des-talitos",
+ "cbc-3des-talitos-hsna",
.cra_blocksize = DES3_EDE_BLOCK_SIZE,
.cra_flags = CRYPTO_ALG_ASYNC,
},
@@ -2458,7 +2449,7 @@ static struct talitos_alg_template driver_algs[] = {
.base = {
.cra_name = "authenc(hmac(sha256),cbc(aes))",
.cra_driver_name = "authenc-hmac-sha256-"
- "cbc-aes-talitos",
+ "cbc-aes-talitos-hsna",
.cra_blocksize = AES_BLOCK_SIZE,
.cra_flags = CRYPTO_ALG_ASYNC,
},
@@ -2502,7 +2493,7 @@ static struct talitos_alg_template driver_algs[] = {
.cra_name = "authenc(hmac(sha256),"
"cbc(des3_ede))",
.cra_driver_name = "authenc-hmac-sha256-"
- "cbc-3des-talitos",
+ "cbc-3des-talitos-hsna",
.cra_blocksize = DES3_EDE_BLOCK_SIZE,
.cra_flags = CRYPTO_ALG_ASYNC,
},
@@ -2628,7 +2619,7 @@ static struct talitos_alg_template driver_algs[] = {
.base = {
.cra_name = "authenc(hmac(md5),cbc(aes))",
.cra_driver_name = "authenc-hmac-md5-"
- "cbc-aes-talitos",
+ "cbc-aes-talitos-hsna",
.cra_blocksize = AES_BLOCK_SIZE,
.cra_flags = CRYPTO_ALG_ASYNC,
},
@@ -2670,7 +2661,7 @@ static struct talitos_alg_template driver_algs[] = {
.base = {
.cra_name = "authenc(hmac(md5),cbc(des3_ede))",
.cra_driver_name = "authenc-hmac-md5-"
- "cbc-3des-talitos",
+ "cbc-3des-talitos-hsna",
.cra_blocksize = DES3_EDE_BLOCK_SIZE,
.cra_flags = CRYPTO_ALG_ASYNC,
},
@@ -3202,7 +3193,10 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev,
alg->cra_priority = t_alg->algt.priority;
else
alg->cra_priority = TALITOS_CRA_PRIORITY;
- alg->cra_alignmask = 0;
+ if (has_ftr_sec1(priv))
+ alg->cra_alignmask = 3;
+ else
+ alg->cra_alignmask = 0;
alg->cra_ctxsize = sizeof(struct talitos_ctx);
alg->cra_flags |= CRYPTO_ALG_KERN_DRIVER_ONLY;
diff --git a/drivers/crypto/talitos.h b/drivers/crypto/talitos.h
index a65a63e..979f6a6 100644
--- a/drivers/crypto/talitos.h
+++ b/drivers/crypto/talitos.h
@@ -65,6 +65,36 @@ struct talitos_desc {
#define TALITOS_DESC_SIZE (sizeof(struct talitos_desc) - sizeof(__be32))
+/*
+ * talitos_edesc - s/w-extended descriptor
+ * @src_nents: number of segments in input scatterlist
+ * @dst_nents: number of segments in output scatterlist
+ * @icv_ool: whether ICV is out-of-line
+ * @iv_dma: dma address of iv for checking continuity and link table
+ * @dma_len: length of dma mapped link_tbl space
+ * @dma_link_tbl: bus physical address of link_tbl/buf
+ * @desc: h/w descriptor
+ * @link_tbl: input and output h/w link tables (if {src,dst}_nents > 1) (SEC2)
+ * @buf: input and output buffeur (if {src,dst}_nents > 1) (SEC1)
+ *
+ * if decrypting (with authcheck), or either one of src_nents or dst_nents
+ * is greater than 1, an integrity check value is concatenated to the end
+ * of link_tbl data
+ */
+struct talitos_edesc {
+ int src_nents;
+ int dst_nents;
+ bool icv_ool;
+ dma_addr_t iv_dma;
+ int dma_len;
+ dma_addr_t dma_link_tbl;
+ struct talitos_desc desc;
+ union {
+ struct talitos_ptr link_tbl[0];
+ u8 buf[0];
+ };
+};
+
/**
* talitos_request - descriptor submission request
* @desc: descriptor pointer (kernel virtual)
diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
index a3f950a..f5ba771 100644
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -1221,6 +1221,7 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)
fence->ops->get_driver_name(fence),
fence->ops->get_timeline_name(fence),
dma_fence_is_signaled(fence) ? "" : "un");
+ dma_fence_put(fence);
}
rcu_read_unlock();
diff --git a/drivers/dma-buf/reservation.c b/drivers/dma-buf/reservation.c
index 6c95f61a..49ab094 100644
--- a/drivers/dma-buf/reservation.c
+++ b/drivers/dma-buf/reservation.c
@@ -416,6 +416,10 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj,
GFP_NOWAIT | __GFP_NOWARN);
if (!nshared) {
rcu_read_unlock();
+
+ dma_fence_put(fence_excl);
+ fence_excl = NULL;
+
nshared = krealloc(shared, sz, GFP_KERNEL);
if (nshared) {
shared = nshared;
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 1c658ec..3f5a01cb 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -2039,27 +2039,6 @@ static int sdma_probe(struct platform_device *pdev)
if (pdata && pdata->script_addrs)
sdma_add_scripts(sdma, pdata->script_addrs);
- if (pdata) {
- ret = sdma_get_firmware(sdma, pdata->fw_name);
- if (ret)
- dev_warn(&pdev->dev, "failed to get firmware from platform data\n");
- } else {
- /*
- * Because that device tree does not encode ROM script address,
- * the RAM script in firmware is mandatory for device tree
- * probe, otherwise it fails.
- */
- ret = of_property_read_string(np, "fsl,sdma-ram-script-name",
- &fw_name);
- if (ret)
- dev_warn(&pdev->dev, "failed to get firmware name\n");
- else {
- ret = sdma_get_firmware(sdma, fw_name);
- if (ret)
- dev_warn(&pdev->dev, "failed to get firmware from device tree\n");
- }
- }
-
sdma->dma_device.dev = &pdev->dev;
sdma->dma_device.device_alloc_chan_resources = sdma_alloc_chan_resources;
@@ -2103,6 +2082,33 @@ static int sdma_probe(struct platform_device *pdev)
of_node_put(spba_bus);
}
+ /*
+ * Kick off firmware loading as the very last step:
+ * attempt to load firmware only if we're not on the error path, because
+ * the firmware callback requires a fully functional and allocated sdma
+ * instance.
+ */
+ if (pdata) {
+ ret = sdma_get_firmware(sdma, pdata->fw_name);
+ if (ret)
+ dev_warn(&pdev->dev, "failed to get firmware from platform data\n");
+ } else {
+ /*
+ * Because that device tree does not encode ROM script address,
+ * the RAM script in firmware is mandatory for device tree
+ * probe, otherwise it fails.
+ */
+ ret = of_property_read_string(np, "fsl,sdma-ram-script-name",
+ &fw_name);
+ if (ret) {
+ dev_warn(&pdev->dev, "failed to get firmware name\n");
+ } else {
+ ret = sdma_get_firmware(sdma, fw_name);
+ if (ret)
+ dev_warn(&pdev->dev, "failed to get firmware from device tree\n");
+ }
+ }
+
return 0;
err_register:
diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c
index c6cbe61..31e9fc1 100644
--- a/drivers/dma/qcom/gpi.c
+++ b/drivers/dma/qcom/gpi.c
@@ -3,7 +3,6 @@
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*/
-#include <asm/dma-iommu.h>
#include <linux/atomic.h>
#include <linux/completion.h>
#include <linux/debugfs.h>
@@ -2534,111 +2533,6 @@ static void gpi_setup_debug(struct gpi_dev *gpi_dev)
}
}
-static struct dma_iommu_mapping *gpi_create_mapping(struct gpi_dev *gpi_dev)
-{
- dma_addr_t base;
- size_t size;
-
- /*
- * If S1_BYPASS enabled then iommu space is not used, however framework
- * still require clients to create a mapping space before attaching. So
- * set to smallest size required by iommu framework.
- */
- if (gpi_dev->smmu_cfg & GPI_SMMU_S1_BYPASS) {
- base = 0;
- size = PAGE_SIZE;
- } else {
- base = gpi_dev->iova_base;
- size = gpi_dev->iova_size;
- }
-
- GPI_LOG(gpi_dev, "Creating iommu mapping of base:0x%llx size:%lu\n",
- base, size);
-
- return __depr_arm_iommu_create_mapping(&platform_bus_type, base, size);
-}
-
-static int gpi_smmu_init(struct gpi_dev *gpi_dev)
-{
- struct dma_iommu_mapping *mapping = NULL;
- int ret;
-
- if (gpi_dev->smmu_cfg) {
-
- /* create mapping table */
- mapping = gpi_create_mapping(gpi_dev);
- if (IS_ERR(mapping)) {
- GPI_ERR(gpi_dev,
- "Failed to create iommu mapping, ret:%ld\n",
- PTR_ERR(mapping));
- return PTR_ERR(mapping);
- }
-
- if (gpi_dev->smmu_cfg & GPI_SMMU_S1_BYPASS) {
- int s1_bypass = 1;
-
- ret = iommu_domain_set_attr(mapping->domain,
- DOMAIN_ATTR_S1_BYPASS, &s1_bypass);
- if (ret) {
- GPI_ERR(gpi_dev,
- "Failed to set attr S1_BYPASS, ret:%d\n",
- ret);
- goto release_mapping;
- }
- }
-
- if (gpi_dev->smmu_cfg & GPI_SMMU_FAST) {
- int fast = 1;
-
- ret = iommu_domain_set_attr(mapping->domain,
- DOMAIN_ATTR_FAST, &fast);
- if (ret) {
- GPI_ERR(gpi_dev,
- "Failed to set attr FAST, ret:%d\n",
- ret);
- goto release_mapping;
- }
- }
-
- if (gpi_dev->smmu_cfg & GPI_SMMU_ATOMIC) {
- int atomic = 1;
-
- ret = iommu_domain_set_attr(mapping->domain,
- DOMAIN_ATTR_ATOMIC, &atomic);
- if (ret) {
- GPI_ERR(gpi_dev,
- "Failed to set attr ATOMIC, ret:%d\n",
- ret);
- goto release_mapping;
- }
- }
-
- ret = __depr_arm_iommu_attach_device(gpi_dev->dev, mapping);
- if (ret) {
- GPI_ERR(gpi_dev,
- "Failed with iommu_attach, ret:%d\n", ret);
- goto release_mapping;
- }
- }
-
- GPI_LOG(gpi_dev, "Setting dma mask to 64\n");
- ret = dma_set_mask(gpi_dev->dev, DMA_BIT_MASK(64));
- if (ret) {
- GPI_ERR(gpi_dev, "Error setting dma_mask to 64, ret:%d\n", ret);
- goto error_set_mask;
- }
-
- return ret;
-
-error_set_mask:
- if (gpi_dev->smmu_cfg)
- __depr_arm_iommu_detach_device(gpi_dev->dev);
-release_mapping:
- if (mapping)
- __depr_arm_iommu_release_mapping(mapping);
- return ret;
-}
-
static int gpi_probe(struct platform_device *pdev)
{
struct gpi_dev *gpi_dev;
@@ -2696,56 +2590,14 @@ static int gpi_probe(struct platform_device *pdev)
return ret;
}
- ret = of_property_read_u32(gpi_dev->dev->of_node, "qcom,smmu-cfg",
- &gpi_dev->smmu_cfg);
- if (ret) {
- GPI_ERR(gpi_dev, "missing 'qcom,smmu-cfg' DT node\n");
- return ret;
- }
-
ret = of_property_read_string(gpi_dev->dev->of_node,
"qcom,iommu-dma", &mode);
- if ((ret == 0) && (strcmp(mode, "disabled") == 0)) {
- if (gpi_dev->smmu_cfg &&
- !(gpi_dev->smmu_cfg & GPI_SMMU_S1_BYPASS)) {
-
- u64 iova_range[2];
-
- ret = of_property_count_elems_of_size(
- gpi_dev->dev->of_node, "qcom,iova-range",
- sizeof(iova_range));
- if (ret != 1) {
- GPI_ERR(gpi_dev,
- "missing or incorrect 'qcom,iova-range' DT node ret:%d\n",
- ret);
- }
-
- ret = of_property_read_u64_array(gpi_dev->dev->of_node,
- "qcom,iova-range", iova_range,
- ARRAY_SIZE(iova_range));
- if (ret) {
- GPI_ERR(gpi_dev,
- "could not read DT prop 'qcom,iova-range\n");
- return ret;
- }
- gpi_dev->iova_base = iova_range[0];
- gpi_dev->iova_size = iova_range[1];
- }
-
- ret = gpi_smmu_init(gpi_dev);
- if (ret) {
- GPI_ERR(gpi_dev,
- "error configuring smmu, ret:%d\n", ret);
- return ret;
- }
- } else {
- ret = dma_set_mask(gpi_dev->dev, DMA_BIT_MASK(64));
- if (ret) {
- GPI_ERR(gpi_dev,
- "Error setting dma_mask to 64, ret:%d\n", ret);
- return ret;
- }
+ ret = dma_set_mask(gpi_dev->dev, DMA_BIT_MASK(64));
+ if (ret) {
+ GPI_ERR(gpi_dev,
+ "Error setting dma_mask to 64, ret:%d\n", ret);
+ return ret;
}
gpi_dev->gpiis = devm_kzalloc(gpi_dev->dev,
diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c
index 0b05a1e..041ce86 100644
--- a/drivers/dma/sh/rcar-dmac.c
+++ b/drivers/dma/sh/rcar-dmac.c
@@ -1164,7 +1164,7 @@ rcar_dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
/* Someone calling slave DMA on a generic channel? */
- if (rchan->mid_rid < 0 || !sg_len) {
+ if (rchan->mid_rid < 0 || !sg_len || !sg_dma_len(sgl)) {
dev_warn(chan->device->dev,
"%s: bad parameter: len=%d, id=%d\n",
__func__, sg_len, rchan->mid_rid);
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index 8219ab8..fb23993 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -981,8 +981,12 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg(
csr |= tdc->slave_id << TEGRA_APBDMA_CSR_REQ_SEL_SHIFT;
}
- if (flags & DMA_PREP_INTERRUPT)
+ if (flags & DMA_PREP_INTERRUPT) {
csr |= TEGRA_APBDMA_CSR_IE_EOC;
+ } else {
+ WARN_ON_ONCE(1);
+ return NULL;
+ }
apb_seq |= TEGRA_APBDMA_APBSEQ_WRAP_WORD_1;
@@ -1124,8 +1128,12 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic(
csr |= tdc->slave_id << TEGRA_APBDMA_CSR_REQ_SEL_SHIFT;
}
- if (flags & DMA_PREP_INTERRUPT)
+ if (flags & DMA_PREP_INTERRUPT) {
csr |= TEGRA_APBDMA_CSR_IE_EOC;
+ } else {
+ WARN_ON_ONCE(1);
+ return NULL;
+ }
apb_seq |= TEGRA_APBDMA_APBSEQ_WRAP_WORD_1;
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index 20374b8..d4545a9 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -26,7 +26,7 @@
static int edac_mc_log_ue = 1;
static int edac_mc_log_ce = 1;
static int edac_mc_panic_on_ue;
-static int edac_mc_poll_msec = 1000;
+static unsigned int edac_mc_poll_msec = 1000;
/* Getter functions for above */
int edac_mc_get_log_ue(void)
@@ -45,30 +45,30 @@ int edac_mc_get_panic_on_ue(void)
}
/* this is temporary */
-int edac_mc_get_poll_msec(void)
+unsigned int edac_mc_get_poll_msec(void)
{
return edac_mc_poll_msec;
}
static int edac_set_poll_msec(const char *val, const struct kernel_param *kp)
{
- unsigned long l;
+ unsigned int i;
int ret;
if (!val)
return -EINVAL;
- ret = kstrtoul(val, 0, &l);
+ ret = kstrtouint(val, 0, &i);
if (ret)
return ret;
- if (l < 1000)
+ if (i < 1000)
return -EINVAL;
- *((unsigned long *)kp->arg) = l;
+ *((unsigned int *)kp->arg) = i;
/* notify edac_mc engine to reset the poll period */
- edac_mc_reset_delay_period(l);
+ edac_mc_reset_delay_period(i);
return 0;
}
@@ -82,7 +82,7 @@ MODULE_PARM_DESC(edac_mc_log_ue,
module_param(edac_mc_log_ce, int, 0644);
MODULE_PARM_DESC(edac_mc_log_ce,
"Log correctable error to console: 0=off 1=on");
-module_param_call(edac_mc_poll_msec, edac_set_poll_msec, param_get_int,
+module_param_call(edac_mc_poll_msec, edac_set_poll_msec, param_get_uint,
&edac_mc_poll_msec, 0644);
MODULE_PARM_DESC(edac_mc_poll_msec, "Polling period in milliseconds");
@@ -404,6 +404,8 @@ static inline int nr_pages_per_csrow(struct csrow_info *csrow)
static int edac_create_csrow_object(struct mem_ctl_info *mci,
struct csrow_info *csrow, int index)
{
+ int err;
+
csrow->dev.type = &csrow_attr_type;
csrow->dev.bus = mci->bus;
csrow->dev.groups = csrow_dev_groups;
@@ -416,7 +418,11 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
edac_dbg(0, "creating (virtual) csrow node %s\n",
dev_name(&csrow->dev));
- return device_add(&csrow->dev);
+ err = device_add(&csrow->dev);
+ if (err)
+ put_device(&csrow->dev);
+
+ return err;
}
/* Create a CSROW object under specifed edac_mc_device */
diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h
index dec88dc..c9f0e73 100644
--- a/drivers/edac/edac_module.h
+++ b/drivers/edac/edac_module.h
@@ -36,7 +36,7 @@ extern int edac_mc_get_log_ue(void);
extern int edac_mc_get_log_ce(void);
extern int edac_mc_get_panic_on_ue(void);
extern int edac_get_poll_msec(void);
-extern int edac_mc_get_poll_msec(void);
+extern unsigned int edac_mc_get_poll_msec(void);
unsigned edac_dimm_info_location(struct dimm_info *dimm, char *buf,
unsigned len);
diff --git a/drivers/esoc/esoc-mdm-4x.c b/drivers/esoc/esoc-mdm-4x.c
index afcf2ce..29edd09 100644
--- a/drivers/esoc/esoc-mdm-4x.c
+++ b/drivers/esoc/esoc-mdm-4x.c
@@ -556,6 +556,7 @@ static irqreturn_t mdm_status_change(int irq, void *dev_id)
cancel_delayed_work(&mdm->mdm2ap_status_check_work);
dev_dbg(dev, "status = 1: mdm is now ready\n");
mdm->ready = true;
+ esoc_clink_evt_notify(ESOC_BOOT_STATE, esoc);
mdm_trigger_dbg(mdm);
queue_work(mdm->mdm_queue, &mdm->mdm_status_work);
if (mdm->get_restart_reason)
diff --git a/drivers/esoc/esoc-mdm-drv.c b/drivers/esoc/esoc-mdm-drv.c
index b5bc12c..3854f25 100644
--- a/drivers/esoc/esoc-mdm-drv.c
+++ b/drivers/esoc/esoc-mdm-drv.c
@@ -28,20 +28,21 @@ enum esoc_pon_state {
enum {
PWR_OFF = 0x1,
- PWR_ON,
- BOOT,
- RUN,
- CRASH,
- IN_DEBUG,
SHUTDOWN,
RESET,
PEER_CRASH,
+ IN_DEBUG,
+ CRASH,
+ PWR_ON,
+ BOOT,
+ RUN,
};
struct mdm_drv {
unsigned int mode;
struct esoc_eng cmd_eng;
struct completion pon_done;
+ struct completion ssr_ready;
struct completion req_eng_wait;
struct esoc_clink *esoc_clink;
enum esoc_pon_state pon_state;
@@ -142,6 +143,14 @@ static void mdm_handle_clink_evt(enum esoc_evt evt,
"ESOC_INVALID_STATE: Calling complete with state: PON_FAIL\n");
mdm_drv->pon_state = PON_FAIL;
complete(&mdm_drv->pon_done);
+ complete(&mdm_drv->ssr_ready);
+ break;
+ case ESOC_BOOT_STATE:
+ if (mdm_drv->mode == PWR_OFF) {
+ esoc_mdm_log(
+ "ESOC_BOOT_STATE: Observed status high from modem.\n");
+ mdm_drv->mode = BOOT;
+ }
break;
case ESOC_RUN_STATE:
esoc_mdm_log(
@@ -149,12 +158,14 @@ static void mdm_handle_clink_evt(enum esoc_evt evt,
mdm_drv->pon_state = PON_SUCCESS;
mdm_drv->mode = RUN,
complete(&mdm_drv->pon_done);
+ complete(&mdm_drv->ssr_ready);
break;
case ESOC_RETRY_PON_EVT:
esoc_mdm_log(
"ESOC_RETRY_PON_EVT: Calling complete with state: PON_RETRY\n");
mdm_drv->pon_state = PON_RETRY;
complete(&mdm_drv->pon_done);
+ complete(&mdm_drv->ssr_ready);
break;
case ESOC_UNEXPECTED_RESET:
esoc_mdm_log("evt_state: ESOC_UNEXPECTED_RESET\n");
@@ -164,19 +175,14 @@ static void mdm_handle_clink_evt(enum esoc_evt evt,
esoc_mdm_log("evt_state: ESOC_ERR_FATAL\n");
/*
- * Modem can crash while we are waiting for pon_done during
- * a subsystem_get(). Setting mode to CRASH will prevent a
- * subsequent subsystem_get() from entering poweron ops. Avoid
- * this by seting mode to CRASH only if device was up and
- * running.
+ * Ignore all modem errfatals if the status is not up
+ * or modem in run state.
*/
- if (mdm_drv->mode == CRASH)
+ if (mdm_drv->mode <= CRASH) {
esoc_mdm_log(
- "Modem in crash state already. Ignoring.\n");
- if (mdm_drv->mode != RUN)
- esoc_mdm_log("Modem not up. Ignoring.\n");
- if (mdm_drv->mode == CRASH || mdm_drv->mode != RUN)
+ "Modem in crash state or not booted. Ignoring.\n");
return;
+ }
queue_work(mdm_drv->mdm_queue, &mdm_drv->ssr_work);
break;
case ESOC_REQ_ENG_ON:
@@ -194,10 +200,15 @@ static void mdm_ssr_fn(struct work_struct *work)
struct mdm_drv *mdm_drv = container_of(work, struct mdm_drv, ssr_work);
struct mdm_ctrl *mdm = get_esoc_clink_data(mdm_drv->esoc_clink);
+ /* Wait for pon to complete. Start SSR only if pon is success */
+ wait_for_completion(&mdm_drv->ssr_ready);
+ if (mdm_drv->pon_state != PON_SUCCESS) {
+ esoc_mdm_log("Got errfatal but ignoring as boot failed\n");
+ return;
+ }
+
esoc_client_link_mdm_crash(mdm_drv->esoc_clink);
-
mdm_wait_for_status_low(mdm, false);
-
esoc_mdm_log("Starting SSR work and setting crash state\n");
mdm_drv->mode = CRASH;
@@ -360,7 +371,9 @@ static void mdm_subsys_retry_powerup_cleanup(struct esoc_clink *esoc_clink,
esoc_client_link_power_off(esoc_clink, poff_flags);
mdm_disable_irqs(mdm);
mdm_drv->pon_state = PON_INIT;
+ mdm_drv->mode = PWR_OFF;
reinit_completion(&mdm_drv->pon_done);
+ reinit_completion(&mdm_drv->ssr_ready);
reinit_completion(&mdm_drv->req_eng_wait);
}
@@ -408,6 +421,7 @@ static int mdm_handle_boot_fail(struct esoc_clink *esoc_clink, u8 *pon_trial)
break;
case BOOT_FAIL_ACTION_NOP:
esoc_mdm_log("Leaving the modem in its curent state\n");
+ mdm_drv->mode = PWR_OFF;
return -EIO;
case BOOT_FAIL_ACTION_SHUTDOWN:
default:
@@ -571,6 +585,7 @@ int esoc_ssr_probe(struct esoc_clink *esoc_clink, struct esoc_drv *drv)
}
esoc_set_drv_data(esoc_clink, mdm_drv);
init_completion(&mdm_drv->pon_done);
+ init_completion(&mdm_drv->ssr_ready);
init_completion(&mdm_drv->req_eng_wait);
INIT_WORK(&mdm_drv->ssr_work, mdm_ssr_fn);
mdm_drv->esoc_clink = esoc_clink;
diff --git a/drivers/firmware/efi/efi-bgrt.c b/drivers/firmware/efi/efi-bgrt.c
index b22ccfb..2bf4d31 100644
--- a/drivers/firmware/efi/efi-bgrt.c
+++ b/drivers/firmware/efi/efi-bgrt.c
@@ -50,11 +50,6 @@ void __init efi_bgrt_init(struct acpi_table_header *table)
bgrt->version);
goto out;
}
- if (bgrt->status & 0xfe) {
- pr_notice("Ignoring BGRT: reserved status bits are non-zero %u\n",
- bgrt->status);
- goto out;
- }
if (bgrt->image_type != 0) {
pr_notice("Ignoring BGRT: invalid image type %u (expected 0)\n",
bgrt->image_type);
diff --git a/drivers/firmware/psci_checker.c b/drivers/firmware/psci_checker.c
index 3469436..cbd53cb 100644
--- a/drivers/firmware/psci_checker.c
+++ b/drivers/firmware/psci_checker.c
@@ -366,16 +366,16 @@ static int suspend_test_thread(void *arg)
for (;;) {
/* Needs to be set first to avoid missing a wakeup. */
set_current_state(TASK_INTERRUPTIBLE);
- if (kthread_should_stop()) {
- __set_current_state(TASK_RUNNING);
+ if (kthread_should_park())
break;
- }
schedule();
}
pr_info("CPU %d suspend test results: success %d, shallow states %d, errors %d\n",
cpu, nb_suspend, nb_shallow_sleep, nb_err);
+ kthread_parkme();
+
return nb_err;
}
@@ -440,8 +440,10 @@ static int suspend_tests(void)
/* Stop and destroy all threads, get return status. */
- for (i = 0; i < nb_threads; ++i)
+ for (i = 0; i < nb_threads; ++i) {
+ err += kthread_park(threads[i]);
err += kthread_stop(threads[i]);
+ }
out:
cpuidle_resume_and_unlock();
kfree(threads);
diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index 1ebcef4..87337fc 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -39,6 +39,7 @@
config FPGA_MGR_ALTERA_PS_SPI
tristate "Altera FPGA Passive Serial over SPI"
depends on SPI
+ select BITREVERSE
help
FPGA manager driver support for Altera Arria/Cyclone/Stratix
using the passive serial interface over SPI.
diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c
index a5ece8e..abb332d 100644
--- a/drivers/gpio/gpio-davinci.c
+++ b/drivers/gpio/gpio-davinci.c
@@ -222,8 +222,9 @@ static int davinci_gpio_probe(struct platform_device *pdev)
for (i = 0; i < nirq; i++) {
chips->irqs[i] = platform_get_irq(pdev, i);
if (chips->irqs[i] < 0) {
- dev_info(dev, "IRQ not populated, err = %d\n",
- chips->irqs[i]);
+ if (chips->irqs[i] != -EPROBE_DEFER)
+ dev_info(dev, "IRQ not populated, err = %d\n",
+ chips->irqs[i]);
return chips->irqs[i];
}
}
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 6fa430d..feabac4 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -837,9 +837,9 @@ static void omap_gpio_irq_shutdown(struct irq_data *d)
raw_spin_lock_irqsave(&bank->lock, flags);
bank->irq_usage &= ~(BIT(offset));
- omap_set_gpio_irqenable(bank, offset, 0);
- omap_clear_gpio_irqstatus(bank, offset);
omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
+ omap_clear_gpio_irqstatus(bank, offset);
+ omap_set_gpio_irqenable(bank, offset, 0);
if (!LINE_USED(bank->mod_usage, offset))
omap_clear_gpio_debounce(bank, offset);
omap_disable_gpio_module(bank, offset);
@@ -881,8 +881,8 @@ static void omap_gpio_mask_irq(struct irq_data *d)
unsigned long flags;
raw_spin_lock_irqsave(&bank->lock, flags);
- omap_set_gpio_irqenable(bank, offset, 0);
omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
+ omap_set_gpio_irqenable(bank, offset, 0);
raw_spin_unlock_irqrestore(&bank->lock, flags);
}
@@ -894,9 +894,6 @@ static void omap_gpio_unmask_irq(struct irq_data *d)
unsigned long flags;
raw_spin_lock_irqsave(&bank->lock, flags);
- if (trigger)
- omap_set_gpio_triggering(bank, offset, trigger);
-
omap_set_gpio_irqenable(bank, offset, 1);
/*
@@ -904,9 +901,13 @@ static void omap_gpio_unmask_irq(struct irq_data *d)
* is cleared, thus after the handler has run. OMAP4 needs this done
* after enabing the interrupt to clear the wakeup status.
*/
- if (bank->level_mask & BIT(offset))
+ if (bank->regs->leveldetect0 && bank->regs->wkup_en &&
+ trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
omap_clear_gpio_irqstatus(bank, offset);
+ if (trigger)
+ omap_set_gpio_triggering(bank, offset, trigger);
+
raw_spin_unlock_irqrestore(&bank->lock, flags);
}
@@ -1687,6 +1688,8 @@ static struct omap_gpio_reg_offs omap4_gpio_regs = {
.clr_dataout = OMAP4_GPIO_CLEARDATAOUT,
.irqstatus = OMAP4_GPIO_IRQSTATUS0,
.irqstatus2 = OMAP4_GPIO_IRQSTATUS1,
+ .irqstatus_raw0 = OMAP4_GPIO_IRQSTATUSRAW0,
+ .irqstatus_raw1 = OMAP4_GPIO_IRQSTATUSRAW1,
.irqenable = OMAP4_GPIO_IRQSTATUSSET0,
.irqenable2 = OMAP4_GPIO_IRQSTATUSSET1,
.set_irqenable = OMAP4_GPIO_IRQSTATUSSET0,
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index f845471..3afb621 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -946,9 +946,11 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
}
if (eflags & GPIOEVENT_REQUEST_RISING_EDGE)
- irqflags |= IRQF_TRIGGER_RISING;
+ irqflags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
+ IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
if (eflags & GPIOEVENT_REQUEST_FALLING_EDGE)
- irqflags |= IRQF_TRIGGER_FALLING;
+ irqflags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
+ IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
irqflags |= IRQF_ONESHOT;
irqflags |= IRQF_SHARED;
@@ -2884,7 +2886,7 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
int gpiod_get_raw_value(const struct gpio_desc *desc)
{
VALIDATE_DESC(desc);
- /* Should be using gpio_get_value_cansleep() */
+ /* Should be using gpiod_get_raw_value_cansleep() */
WARN_ON(desc->gdev->chip->can_sleep);
return gpiod_get_raw_value_commit(desc);
}
@@ -2905,7 +2907,7 @@ int gpiod_get_value(const struct gpio_desc *desc)
int value;
VALIDATE_DESC(desc);
- /* Should be using gpio_get_value_cansleep() */
+ /* Should be using gpiod_get_value_cansleep() */
WARN_ON(desc->gdev->chip->can_sleep);
value = gpiod_get_raw_value_commit(desc);
@@ -3130,7 +3132,7 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
void gpiod_set_raw_value(struct gpio_desc *desc, int value)
{
VALIDATE_DESC_VOID(desc);
- /* Should be using gpiod_set_value_cansleep() */
+ /* Should be using gpiod_set_raw_value_cansleep() */
WARN_ON(desc->gdev->chip->can_sleep);
gpiod_set_raw_value_commit(desc, value);
}
@@ -3171,6 +3173,7 @@ static void gpiod_set_value_nocheck(struct gpio_desc *desc, int value)
void gpiod_set_value(struct gpio_desc *desc, int value)
{
VALIDATE_DESC_VOID(desc);
+ /* Should be using gpiod_set_value_cansleep() */
WARN_ON(desc->gdev->chip->can_sleep);
gpiod_set_value_nocheck(desc, value);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
index 72f8018..ede27da 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
@@ -1037,6 +1037,9 @@ static int gmc_v9_0_gart_enable(struct amdgpu_device *adev)
tmp = RREG32_SOC15(HDP, 0, mmHDP_HOST_PATH_CNTL);
WREG32_SOC15(HDP, 0, mmHDP_HOST_PATH_CNTL, tmp);
+ WREG32_SOC15(HDP, 0, mmHDP_NONSURFACE_BASE, (adev->gmc.vram_start >> 8));
+ WREG32_SOC15(HDP, 0, mmHDP_NONSURFACE_BASE_HI, (adev->gmc.vram_start >> 40));
+
/* After HDP is initialized, flush HDP.*/
adev->nbio_funcs->hdp_flush(adev, NULL);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
index 4f22e74..189212c 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
@@ -1268,12 +1268,17 @@ int amdkfd_fence_wait_timeout(unsigned int *fence_addr,
return 0;
}
-static int unmap_sdma_queues(struct device_queue_manager *dqm,
- unsigned int sdma_engine)
+static int unmap_sdma_queues(struct device_queue_manager *dqm)
{
- return pm_send_unmap_queue(&dqm->packets, KFD_QUEUE_TYPE_SDMA,
- KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0, false,
- sdma_engine);
+ int i, retval = 0;
+
+ for (i = 0; i < dqm->dev->device_info->num_sdma_engines; i++) {
+ retval = pm_send_unmap_queue(&dqm->packets, KFD_QUEUE_TYPE_SDMA,
+ KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0, false, i);
+ if (retval)
+ return retval;
+ }
+ return retval;
}
/* dqm->lock mutex has to be locked before calling this function */
@@ -1312,10 +1317,8 @@ static int unmap_queues_cpsch(struct device_queue_manager *dqm,
pr_debug("Before destroying queues, sdma queue count is : %u\n",
dqm->sdma_queue_count);
- if (dqm->sdma_queue_count > 0) {
- unmap_sdma_queues(dqm, 0);
- unmap_sdma_queues(dqm, 1);
- }
+ if (dqm->sdma_queue_count > 0)
+ unmap_sdma_queues(dqm);
retval = pm_send_unmap_queue(&dqm->packets, KFD_QUEUE_TYPE_COMPUTE,
filter, filter_param, false, 0);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
index 0cedb37..985bebd 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
@@ -75,6 +75,7 @@ static int init_mqd(struct mqd_manager *mm, void **mqd,
struct v9_mqd *m;
struct kfd_dev *kfd = mm->dev;
+ *mqd_mem_obj = NULL;
/* From V9, for CWSR, the control stack is located on the next page
* boundary after the mqd, we will use the gtt allocation function
* instead of sub-allocation function.
@@ -92,8 +93,10 @@ static int init_mqd(struct mqd_manager *mm, void **mqd,
} else
retval = kfd_gtt_sa_allocate(mm->dev, sizeof(struct v9_mqd),
mqd_mem_obj);
- if (retval != 0)
+ if (retval) {
+ kfree(*mqd_mem_obj);
return -ENOMEM;
+ }
m = (struct v9_mqd *) (*mqd_mem_obj)->cpu_ptr;
addr = (*mqd_mem_obj)->gpu_addr;
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 dac7978..221de24 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -3644,6 +3644,13 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
{
struct amdgpu_device *adev = dm->ddev->dev_private;
+ /*
+ * Some of the properties below require access to state, like bpc.
+ * Allocate some default initial connector state with our reset helper.
+ */
+ if (aconnector->base.funcs->reset)
+ aconnector->base.funcs->reset(&aconnector->base);
+
aconnector->connector_id = link_index;
aconnector->dc_link = link;
aconnector->base.interlace_allowed = false;
@@ -3811,9 +3818,6 @@ static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm,
&aconnector->base,
&amdgpu_dm_connector_helper_funcs);
- if (aconnector->base.funcs->reset)
- aconnector->base.funcs->reset(&aconnector->base);
-
amdgpu_dm_connector_init_helper(
dm,
aconnector,
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c b/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c
index 29294db..070ab56 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c
@@ -474,6 +474,8 @@ void dce_abm_destroy(struct abm **abm)
{
struct dce_abm *abm_dce = TO_DCE_ABM(*abm);
+ abm_dce->base.funcs->set_abm_immediate_disable(*abm);
+
kfree(abm_dce);
*abm = NULL;
}
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 53ccacf..c3ad2bb 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
@@ -242,6 +242,9 @@ static void build_prescale_params(struct ipp_prescale_params *prescale_params,
prescale_params->mode = IPP_PRESCALE_MODE_FIXED_UNSIGNED;
switch (plane_state->format) {
+ case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
+ prescale_params->scale = 0x2082;
+ break;
case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
prescale_params->scale = 0x2020;
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 7736ef1..ead221c 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
@@ -23,6 +23,7 @@
*
*/
+#include <linux/delay.h>
#include "dm_services.h"
#include "core_types.h"
#include "resource.h"
diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c
index e59a135..0cc6dbb 100644
--- a/drivers/gpu/drm/bridge/sii902x.c
+++ b/drivers/gpu/drm/bridge/sii902x.c
@@ -261,10 +261,11 @@ static void sii902x_bridge_mode_set(struct drm_bridge *bridge,
struct regmap *regmap = sii902x->regmap;
u8 buf[HDMI_INFOFRAME_SIZE(AVI)];
struct hdmi_avi_infoframe frame;
+ u16 pixel_clock_10kHz = adj->clock / 10;
int ret;
- buf[0] = adj->clock;
- buf[1] = adj->clock >> 8;
+ buf[0] = pixel_clock_10kHz & 0xff;
+ buf[1] = pixel_clock_10kHz >> 8;
buf[2] = adj->vrefresh;
buf[3] = 0x00;
buf[4] = adj->hdisplay;
diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index 3915473..aaca524 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -1149,6 +1149,13 @@ static int tc_connector_get_modes(struct drm_connector *connector)
struct tc_data *tc = connector_to_tc(connector);
struct edid *edid;
unsigned int count;
+ int ret;
+
+ ret = tc_get_display_props(tc);
+ if (ret < 0) {
+ dev_err(tc->dev, "failed to read display props: %d\n", ret);
+ return 0;
+ }
if (tc->panel && tc->panel->funcs && tc->panel->funcs->get_modes) {
count = tc->panel->funcs->get_modes(tc->panel);
diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c
index e2f775d..21bec45 100644
--- a/drivers/gpu/drm/drm_bufs.c
+++ b/drivers/gpu/drm/drm_bufs.c
@@ -1321,7 +1321,10 @@ static int copy_one_buf(void *data, int count, struct drm_buf_entry *from)
.size = from->buf_size,
.low_mark = from->low_mark,
.high_mark = from->high_mark};
- return copy_to_user(to, &v, offsetof(struct drm_buf_desc, flags));
+
+ if (copy_to_user(to, &v, offsetof(struct drm_buf_desc, flags)))
+ return -EFAULT;
+ return 0;
}
int drm_legacy_infobufs(struct drm_device *dev, void *data,
diff --git a/drivers/gpu/drm/drm_debugfs_crc.c b/drivers/gpu/drm/drm_debugfs_crc.c
index 9996119..c88e5ff 100644
--- a/drivers/gpu/drm/drm_debugfs_crc.c
+++ b/drivers/gpu/drm/drm_debugfs_crc.c
@@ -379,12 +379,13 @@ int drm_crtc_add_crc_entry(struct drm_crtc *crtc, bool has_frame,
struct drm_crtc_crc *crc = &crtc->crc;
struct drm_crtc_crc_entry *entry;
int head, tail;
+ unsigned long flags;
- spin_lock(&crc->lock);
+ spin_lock_irqsave(&crc->lock, flags);
/* Caller may not have noticed yet that userspace has stopped reading */
if (!crc->entries) {
- spin_unlock(&crc->lock);
+ spin_unlock_irqrestore(&crc->lock, flags);
return -EINVAL;
}
@@ -395,7 +396,7 @@ int drm_crtc_add_crc_entry(struct drm_crtc *crtc, bool has_frame,
bool was_overflow = crc->overflow;
crc->overflow = true;
- spin_unlock(&crc->lock);
+ spin_unlock_irqrestore(&crc->lock, flags);
if (!was_overflow)
DRM_ERROR("Overflow of CRC buffer, userspace reads too slow.\n");
@@ -411,7 +412,7 @@ int drm_crtc_add_crc_entry(struct drm_crtc *crtc, bool has_frame,
head = (head + 1) & (DRM_CRC_ENTRIES_NR - 1);
crc->head = head;
- spin_unlock(&crc->lock);
+ spin_unlock_irqrestore(&crc->lock, flags);
wake_up_interruptible(&crc->wq);
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 65c4631..650554a 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -1359,6 +1359,7 @@ MODULE_PARM_DESC(edid_fixup,
static void drm_get_displayid(struct drm_connector *connector,
struct edid *edid);
+static int validate_displayid(u8 *displayid, int length, int idx);
static int drm_edid_block_checksum(const u8 *raw_edid)
{
@@ -2952,16 +2953,46 @@ static u8 *drm_find_edid_extension(const struct edid *edid, int ext_id)
return edid_ext;
}
-static u8 *drm_find_cea_extension(const struct edid *edid)
-{
- return drm_find_edid_extension(edid, CEA_EXT);
-}
static u8 *drm_find_displayid_extension(const struct edid *edid)
{
return drm_find_edid_extension(edid, DISPLAYID_EXT);
}
+static u8 *drm_find_cea_extension(const struct edid *edid)
+{
+ int ret;
+ int idx = 1;
+ int length = EDID_LENGTH;
+ struct displayid_block *block;
+ u8 *cea;
+ u8 *displayid;
+
+ /* Look for a top level CEA extension block */
+ cea = drm_find_edid_extension(edid, CEA_EXT);
+ if (cea)
+ return cea;
+
+ /* CEA blocks can also be found embedded in a DisplayID block */
+ displayid = drm_find_displayid_extension(edid);
+ if (!displayid)
+ return NULL;
+
+ ret = validate_displayid(displayid, length, idx);
+ if (ret)
+ return NULL;
+
+ idx += sizeof(struct displayid_hdr);
+ for_each_displayid_db(displayid, block, idx, length) {
+ if (block->tag == DATA_BLOCK_CTA) {
+ cea = (u8 *)block;
+ break;
+ }
+ }
+
+ return cea;
+}
+
/*
* Calculate the alternate clock for the CEA mode
* (60Hz vs. 59.94Hz etc.)
@@ -3685,13 +3716,38 @@ cea_revision(const u8 *cea)
static int
cea_db_offsets(const u8 *cea, int *start, int *end)
{
- /* Data block offset in CEA extension block */
- *start = 4;
- *end = cea[2];
- if (*end == 0)
- *end = 127;
- if (*end < 4 || *end > 127)
- return -ERANGE;
+ /* DisplayID CTA extension blocks and top-level CEA EDID
+ * block header definitions differ in the following bytes:
+ * 1) Byte 2 of the header specifies length differently,
+ * 2) Byte 3 is only present in the CEA top level block.
+ *
+ * The different definitions for byte 2 follow.
+ *
+ * DisplayID CTA extension block defines byte 2 as:
+ * Number of payload bytes
+ *
+ * CEA EDID block defines byte 2 as:
+ * Byte number (decimal) within this block where the 18-byte
+ * DTDs begin. If no non-DTD data is present in this extension
+ * block, the value should be set to 04h (the byte after next).
+ * If set to 00h, there are no DTDs present in this block and
+ * no non-DTD data.
+ */
+ if (cea[0] == DATA_BLOCK_CTA) {
+ *start = 3;
+ *end = *start + cea[2];
+ } else if (cea[0] == CEA_EXT) {
+ /* Data block offset in CEA extension block */
+ *start = 4;
+ *end = cea[2];
+ if (*end == 0)
+ *end = 127;
+ if (*end < 4 || *end > 127)
+ return -ERANGE;
+ } else {
+ return -ENOTSUPP;
+ }
+
return 0;
}
@@ -5503,6 +5559,9 @@ static int drm_parse_display_id(struct drm_connector *connector,
case DATA_BLOCK_TYPE_1_DETAILED_TIMING:
/* handled in mode gathering code. */
break;
+ case DATA_BLOCK_CTA:
+ /* handled in the cea parser code. */
+ break;
default:
DRM_DEBUG_KMS("found DisplayID tag 0x%x, unhandled\n", block->tag);
break;
diff --git a/drivers/gpu/drm/drm_edid_load.c b/drivers/gpu/drm/drm_edid_load.c
index a491509..a0e107a 100644
--- a/drivers/gpu/drm/drm_edid_load.c
+++ b/drivers/gpu/drm/drm_edid_load.c
@@ -290,6 +290,8 @@ struct edid *drm_load_edid_firmware(struct drm_connector *connector)
* the last one found one as a fallback.
*/
fwstr = kstrdup(edid_firmware, GFP_KERNEL);
+ if (!fwstr)
+ return ERR_PTR(-ENOMEM);
edidstr = fwstr;
while ((edidname = strsep(&edidstr, ","))) {
diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c
index 67b1fca..138680b 100644
--- a/drivers/gpu/drm/drm_ioc32.c
+++ b/drivers/gpu/drm/drm_ioc32.c
@@ -372,7 +372,10 @@ static int copy_one_buf32(void *data, int count, struct drm_buf_entry *from)
.size = from->buf_size,
.low_mark = from->low_mark,
.high_mark = from->high_mark};
- return copy_to_user(to + count, &v, offsetof(drm_buf_desc32_t, flags));
+
+ if (copy_to_user(to + count, &v, offsetof(drm_buf_desc32_t, flags)))
+ return -EFAULT;
+ return 0;
}
static int drm_legacy_infobufs32(struct drm_device *dev, void *data,
diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c
index 12e4203..66abe06 100644
--- a/drivers/gpu/drm/i915/gvt/kvmgt.c
+++ b/drivers/gpu/drm/i915/gvt/kvmgt.c
@@ -1748,6 +1748,18 @@ int kvmgt_dma_map_guest_page(unsigned long handle, unsigned long gfn,
ret = __gvt_cache_add(info->vgpu, gfn, *dma_addr, size);
if (ret)
goto err_unmap;
+ } else if (entry->size != size) {
+ /* the same gfn with different size: unmap and re-map */
+ gvt_dma_unmap_page(vgpu, gfn, entry->dma_addr, entry->size);
+ __gvt_cache_remove_entry(vgpu, entry);
+
+ ret = gvt_dma_map_page(vgpu, gfn, dma_addr, size);
+ if (ret)
+ goto err_unlock;
+
+ ret = __gvt_cache_add(info->vgpu, gfn, *dma_addr, size);
+ if (ret)
+ goto err_unmap;
} else {
kref_get(&entry->ref);
*dma_addr = entry->dma_addr;
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 8b0605f..89bd242 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -1336,16 +1336,24 @@ static int msm_pdev_probe(struct platform_device *pdev)
ret = add_gpu_components(&pdev->dev, &match);
if (ret)
- return ret;
+ goto fail;
/* on all devices that I am aware of, iommu's which can map
* any address the cpu can see are used:
*/
ret = dma_set_mask_and_coherent(&pdev->dev, ~0);
if (ret)
- return ret;
+ goto fail;
- return component_master_add_with_match(&pdev->dev, &msm_drm_ops, match);
+ ret = component_master_add_with_match(&pdev->dev, &msm_drm_ops, match);
+ if (ret)
+ goto fail;
+
+ return 0;
+
+fail:
+ of_platform_depopulate(&pdev->dev);
+ return ret;
}
static int msm_pdev_remove(struct platform_device *pdev)
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 247f72c..fb0094f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -251,7 +251,7 @@ nouveau_conn_reset(struct drm_connector *connector)
return;
if (connector->state)
- __drm_atomic_helper_connector_destroy_state(connector->state);
+ nouveau_conn_atomic_destroy_state(connector, connector->state);
__drm_atomic_helper_connector_reset(connector, &asyc->state);
asyc->dither.mode = DITHERING_MODE_AUTO;
asyc->dither.depth = DITHERING_DEPTH_AUTO;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c
index ecacb22..7193450 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c
@@ -185,6 +185,25 @@ nvkm_i2c_fini(struct nvkm_subdev *subdev, bool suspend)
}
static int
+nvkm_i2c_preinit(struct nvkm_subdev *subdev)
+{
+ struct nvkm_i2c *i2c = nvkm_i2c(subdev);
+ struct nvkm_i2c_bus *bus;
+ struct nvkm_i2c_pad *pad;
+
+ /*
+ * We init our i2c busses as early as possible, since they may be
+ * needed by the vbios init scripts on some cards
+ */
+ list_for_each_entry(pad, &i2c->pad, head)
+ nvkm_i2c_pad_init(pad);
+ list_for_each_entry(bus, &i2c->bus, head)
+ nvkm_i2c_bus_init(bus);
+
+ return 0;
+}
+
+static int
nvkm_i2c_init(struct nvkm_subdev *subdev)
{
struct nvkm_i2c *i2c = nvkm_i2c(subdev);
@@ -238,6 +257,7 @@ nvkm_i2c_dtor(struct nvkm_subdev *subdev)
static const struct nvkm_subdev_func
nvkm_i2c = {
.dtor = nvkm_i2c_dtor,
+ .preinit = nvkm_i2c_preinit,
.init = nvkm_i2c_init,
.fini = nvkm_i2c_fini,
.intr = nvkm_i2c_intr,
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index 97964f7..b1d41c4 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -2803,7 +2803,14 @@ static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi)
dsi->format = desc->format;
dsi->lanes = desc->lanes;
- return mipi_dsi_attach(dsi);
+ err = mipi_dsi_attach(dsi);
+ if (err) {
+ struct panel_simple *panel = dev_get_drvdata(&dsi->dev);
+
+ drm_panel_remove(&panel->base);
+ }
+
+ return err;
}
static int panel_simple_dsi_remove(struct mipi_dsi_device *dsi)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index f8f9ae6..873624a 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -880,7 +880,8 @@ static bool vop_crtc_mode_fixup(struct drm_crtc *crtc,
struct vop *vop = to_vop(crtc);
adjusted_mode->clock =
- clk_round_rate(vop->dclk, mode->clock * 1000) / 1000;
+ DIV_ROUND_UP(clk_round_rate(vop->dclk, mode->clock * 1000),
+ 1000);
return true;
}
diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c
index 54e767b..f28703d 100644
--- a/drivers/gpu/drm/udl/udl_drv.c
+++ b/drivers/gpu/drm/udl/udl_drv.c
@@ -47,10 +47,16 @@ static const struct file_operations udl_driver_fops = {
.llseek = noop_llseek,
};
+static void udl_driver_release(struct drm_device *dev)
+{
+ udl_fini(dev);
+ udl_modeset_cleanup(dev);
+ drm_dev_fini(dev);
+ kfree(dev);
+}
+
static struct drm_driver driver = {
.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
- .load = udl_driver_load,
- .unload = udl_driver_unload,
.release = udl_driver_release,
/* gem hooks */
@@ -74,28 +80,56 @@ static struct drm_driver driver = {
.patchlevel = DRIVER_PATCHLEVEL,
};
+static struct udl_device *udl_driver_create(struct usb_interface *interface)
+{
+ struct usb_device *udev = interface_to_usbdev(interface);
+ struct udl_device *udl;
+ int r;
+
+ udl = kzalloc(sizeof(*udl), GFP_KERNEL);
+ if (!udl)
+ return ERR_PTR(-ENOMEM);
+
+ r = drm_dev_init(&udl->drm, &driver, &interface->dev);
+ if (r) {
+ kfree(udl);
+ return ERR_PTR(r);
+ }
+
+ udl->udev = udev;
+ udl->drm.dev_private = udl;
+
+ r = udl_init(udl);
+ if (r) {
+ drm_dev_fini(&udl->drm);
+ kfree(udl);
+ return ERR_PTR(r);
+ }
+
+ usb_set_intfdata(interface, udl);
+ return udl;
+}
+
static int udl_usb_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
- struct usb_device *udev = interface_to_usbdev(interface);
- struct drm_device *dev;
int r;
+ struct udl_device *udl;
- dev = drm_dev_alloc(&driver, &interface->dev);
- if (IS_ERR(dev))
- return PTR_ERR(dev);
+ udl = udl_driver_create(interface);
+ if (IS_ERR(udl))
+ return PTR_ERR(udl);
- r = drm_dev_register(dev, (unsigned long)udev);
+ r = drm_dev_register(&udl->drm, 0);
if (r)
goto err_free;
- usb_set_intfdata(interface, dev);
- DRM_INFO("Initialized udl on minor %d\n", dev->primary->index);
+ DRM_INFO("Initialized udl on minor %d\n", udl->drm.primary->index);
return 0;
err_free:
- drm_dev_unref(dev);
+ drm_dev_put(&udl->drm);
return r;
}
diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h
index 4ae67d8..35c1f33 100644
--- a/drivers/gpu/drm/udl/udl_drv.h
+++ b/drivers/gpu/drm/udl/udl_drv.h
@@ -50,8 +50,8 @@ struct urb_list {
struct udl_fbdev;
struct udl_device {
+ struct drm_device drm;
struct device *dev;
- struct drm_device *ddev;
struct usb_device *udev;
struct drm_crtc *crtc;
@@ -71,6 +71,8 @@ struct udl_device {
atomic_t cpu_kcycles_used; /* transpired during pixel processing */
};
+#define to_udl(x) container_of(x, struct udl_device, drm)
+
struct udl_gem_object {
struct drm_gem_object base;
struct page **pages;
@@ -102,9 +104,8 @@ struct urb *udl_get_urb(struct drm_device *dev);
int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len);
void udl_urb_completion(struct urb *urb);
-int udl_driver_load(struct drm_device *dev, unsigned long flags);
-void udl_driver_unload(struct drm_device *dev);
-void udl_driver_release(struct drm_device *dev);
+int udl_init(struct udl_device *udl);
+void udl_fini(struct drm_device *dev);
int udl_fbdev_init(struct drm_device *dev);
void udl_fbdev_cleanup(struct drm_device *dev);
diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c
index dd9ffde..4ab101b 100644
--- a/drivers/gpu/drm/udl/udl_fb.c
+++ b/drivers/gpu/drm/udl/udl_fb.c
@@ -82,7 +82,7 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y,
int width, int height)
{
struct drm_device *dev = fb->base.dev;
- struct udl_device *udl = dev->dev_private;
+ struct udl_device *udl = to_udl(dev);
int i, ret;
char *cmd;
cycles_t start_cycles, end_cycles;
@@ -210,10 +210,10 @@ static int udl_fb_open(struct fb_info *info, int user)
{
struct udl_fbdev *ufbdev = info->par;
struct drm_device *dev = ufbdev->ufb.base.dev;
- struct udl_device *udl = dev->dev_private;
+ struct udl_device *udl = to_udl(dev);
/* If the USB device is gone, we don't accept new opens */
- if (drm_dev_is_unplugged(udl->ddev))
+ if (drm_dev_is_unplugged(&udl->drm))
return -ENODEV;
ufbdev->fb_count++;
@@ -441,7 +441,7 @@ static void udl_fbdev_destroy(struct drm_device *dev,
int udl_fbdev_init(struct drm_device *dev)
{
- struct udl_device *udl = dev->dev_private;
+ struct udl_device *udl = to_udl(dev);
int bpp_sel = fb_bpp;
struct udl_fbdev *ufbdev;
int ret;
@@ -480,7 +480,7 @@ int udl_fbdev_init(struct drm_device *dev)
void udl_fbdev_cleanup(struct drm_device *dev)
{
- struct udl_device *udl = dev->dev_private;
+ struct udl_device *udl = to_udl(dev);
if (!udl->fbdev)
return;
@@ -491,7 +491,7 @@ void udl_fbdev_cleanup(struct drm_device *dev)
void udl_fbdev_unplug(struct drm_device *dev)
{
- struct udl_device *udl = dev->dev_private;
+ struct udl_device *udl = to_udl(dev);
struct udl_fbdev *ufbdev;
if (!udl->fbdev)
return;
diff --git a/drivers/gpu/drm/udl/udl_gem.c b/drivers/gpu/drm/udl/udl_gem.c
index bb7b584..3b3e176 100644
--- a/drivers/gpu/drm/udl/udl_gem.c
+++ b/drivers/gpu/drm/udl/udl_gem.c
@@ -203,7 +203,7 @@ int udl_gem_mmap(struct drm_file *file, struct drm_device *dev,
{
struct udl_gem_object *gobj;
struct drm_gem_object *obj;
- struct udl_device *udl = dev->dev_private;
+ struct udl_device *udl = to_udl(dev);
int ret = 0;
mutex_lock(&udl->gem_lock);
diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c
index 19055dd..8d22b6c 100644
--- a/drivers/gpu/drm/udl/udl_main.c
+++ b/drivers/gpu/drm/udl/udl_main.c
@@ -29,7 +29,7 @@
static int udl_parse_vendor_descriptor(struct drm_device *dev,
struct usb_device *usbdev)
{
- struct udl_device *udl = dev->dev_private;
+ struct udl_device *udl = to_udl(dev);
char *desc;
char *buf;
char *desc_end;
@@ -165,7 +165,7 @@ void udl_urb_completion(struct urb *urb)
static void udl_free_urb_list(struct drm_device *dev)
{
- struct udl_device *udl = dev->dev_private;
+ struct udl_device *udl = to_udl(dev);
int count = udl->urbs.count;
struct list_head *node;
struct urb_node *unode;
@@ -198,7 +198,7 @@ static void udl_free_urb_list(struct drm_device *dev)
static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size)
{
- struct udl_device *udl = dev->dev_private;
+ struct udl_device *udl = to_udl(dev);
struct urb *urb;
struct urb_node *unode;
char *buf;
@@ -262,7 +262,7 @@ static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size)
struct urb *udl_get_urb(struct drm_device *dev)
{
- struct udl_device *udl = dev->dev_private;
+ struct udl_device *udl = to_udl(dev);
int ret = 0;
struct list_head *entry;
struct urb_node *unode;
@@ -295,7 +295,7 @@ struct urb *udl_get_urb(struct drm_device *dev)
int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len)
{
- struct udl_device *udl = dev->dev_private;
+ struct udl_device *udl = to_udl(dev);
int ret;
BUG_ON(len > udl->urbs.size);
@@ -310,20 +310,12 @@ int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len)
return ret;
}
-int udl_driver_load(struct drm_device *dev, unsigned long flags)
+int udl_init(struct udl_device *udl)
{
- struct usb_device *udev = (void*)flags;
- struct udl_device *udl;
+ struct drm_device *dev = &udl->drm;
int ret = -ENOMEM;
DRM_DEBUG("\n");
- udl = kzalloc(sizeof(struct udl_device), GFP_KERNEL);
- if (!udl)
- return -ENOMEM;
-
- udl->udev = udev;
- udl->ddev = dev;
- dev->dev_private = udl;
mutex_init(&udl->gem_lock);
@@ -357,7 +349,6 @@ int udl_driver_load(struct drm_device *dev, unsigned long flags)
err:
if (udl->urbs.count)
udl_free_urb_list(dev);
- kfree(udl);
DRM_ERROR("%d\n", ret);
return ret;
}
@@ -368,9 +359,9 @@ int udl_drop_usb(struct drm_device *dev)
return 0;
}
-void udl_driver_unload(struct drm_device *dev)
+void udl_fini(struct drm_device *dev)
{
- struct udl_device *udl = dev->dev_private;
+ struct udl_device *udl = to_udl(dev);
drm_kms_helper_poll_fini(dev);
@@ -378,12 +369,4 @@ void udl_driver_unload(struct drm_device *dev)
udl_free_urb_list(dev);
udl_fbdev_cleanup(dev);
- kfree(udl);
-}
-
-void udl_driver_release(struct drm_device *dev)
-{
- udl_modeset_cleanup(dev);
- drm_dev_fini(dev);
- kfree(dev);
}
diff --git a/drivers/gpu/drm/virtio/virtgpu_ioctl.c b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
index 7bdf6f0..8d2f5de 100644
--- a/drivers/gpu/drm/virtio/virtgpu_ioctl.c
+++ b/drivers/gpu/drm/virtio/virtgpu_ioctl.c
@@ -528,6 +528,9 @@ static int virtio_gpu_get_caps_ioctl(struct drm_device *dev,
if (!ret)
return -EBUSY;
+ /* is_valid check must proceed before copy of the cache entry. */
+ smp_rmb();
+
ptr = cache_ent->caps_cache;
copy_exit:
diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c
index 020070d4..c8a581b 100644
--- a/drivers/gpu/drm/virtio/virtgpu_vq.c
+++ b/drivers/gpu/drm/virtio/virtgpu_vq.c
@@ -588,6 +588,8 @@ static void virtio_gpu_cmd_capset_cb(struct virtio_gpu_device *vgdev,
cache_ent->id == le32_to_cpu(cmd->capset_id)) {
memcpy(cache_ent->caps_cache, resp->capset_data,
cache_ent->size);
+ /* Copy must occur before is_valid is signalled. */
+ smp_wmb();
atomic_set(&cache_ent->is_valid, 1);
break;
}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 82ae687..05a8008 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -789,6 +789,9 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
if (unlikely(ret != 0))
goto out_err0;
+ dma_set_max_seg_size(dev->dev, min_t(unsigned int, U32_MAX & PAGE_MASK,
+ SCATTERLIST_MAX_SEGMENT));
+
if (dev_priv->capabilities & SVGA_CAP_GMR2) {
DRM_INFO("Max GMR ids is %u\n",
(unsigned)dev_priv->max_gmr_ids);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c
index 31786b2..f388ad5 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_buffer.c
@@ -448,11 +448,11 @@ static int vmw_ttm_map_dma(struct vmw_ttm_tt *vmw_tt)
if (unlikely(ret != 0))
return ret;
- ret = sg_alloc_table_from_pages(&vmw_tt->sgt, vsgt->pages,
- vsgt->num_pages, 0,
- (unsigned long)
- vsgt->num_pages << PAGE_SHIFT,
- GFP_KERNEL);
+ ret = __sg_alloc_table_from_pages
+ (&vmw_tt->sgt, vsgt->pages, vsgt->num_pages, 0,
+ (unsigned long) vsgt->num_pages << PAGE_SHIFT,
+ dma_get_max_seg_size(dev_priv->dev->dev),
+ GFP_KERNEL);
if (unlikely(ret != 0))
goto out_sg_alloc_fail;
diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c
index 815bdb4..0121fe7 100644
--- a/drivers/gpu/host1x/bus.c
+++ b/drivers/gpu/host1x/bus.c
@@ -423,6 +423,9 @@ static int host1x_device_add(struct host1x *host1x,
of_dma_configure(&device->dev, host1x->dev->of_node, true);
+ device->dev.dma_parms = &device->dma_parms;
+ dma_set_max_seg_size(&device->dev, SZ_4M);
+
err = host1x_device_parse_dt(device, driver);
if (err < 0) {
kfree(device);
diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c
index 67cc820..fb79e11 100644
--- a/drivers/gpu/ipu-v3/ipu-ic.c
+++ b/drivers/gpu/ipu-v3/ipu-ic.c
@@ -257,7 +257,7 @@ static int init_csc(struct ipu_ic *ic,
writel(param, base++);
param = ((a[0] & 0x1fe0) >> 5) | (params->scale << 8) |
- (params->sat << 9);
+ (params->sat << 10);
writel(param, base++);
param = ((a[1] & 0x1f) << 27) | ((c[0][1] & 0x1ff) << 18) |
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index 733f455..48a92cf 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -2344,6 +2344,14 @@ static void a6xx_platform_setup(struct adreno_device *adreno_dev)
/* Check efuse bits for various capabilties */
a6xx_check_features(adreno_dev);
+
+ /*
+ * A640 GPUs used a fuse to determine which frequency plan to
+ * use for the GPU. For A650 GPUs enable using higher frequencies
+ * based on the LM feature flag.
+ */
+ if (adreno_is_a650(adreno_dev) && ADRENO_FEATURE(adreno_dev, ADRENO_LM))
+ adreno_dev->speed_bin = 1;
}
diff --git a/drivers/gpu/msm/adreno_llc.h b/drivers/gpu/msm/adreno_llc.h
index cac4d17..5a2c05d 100644
--- a/drivers/gpu/msm/adreno_llc.h
+++ b/drivers/gpu/msm/adreno_llc.h
@@ -73,7 +73,7 @@ static inline bool adreno_llc_supported(void)
static inline void *adreno_llc_getd(u32 uid)
{
- return ERR_PTR(-ENODEV);
+ return ERR_PTR(-ENOENT);
}
static inline void adreno_llc_putd(void *desc)
diff --git a/drivers/gpu/msm/kgsl_rgmu.c b/drivers/gpu/msm/kgsl_rgmu.c
index a32a695..e3426e1e 100644
--- a/drivers/gpu/msm/kgsl_rgmu.c
+++ b/drivers/gpu/msm/kgsl_rgmu.c
@@ -193,20 +193,20 @@ static int rgmu_enable_clks(struct kgsl_device *device)
}
#define CX_GDSC_TIMEOUT 5000 /* ms */
-static int rgmu_disable_gdsc(struct kgsl_device *device)
+static void rgmu_disable_gdsc(struct kgsl_device *device)
{
struct rgmu_device *rgmu = KGSL_RGMU_DEVICE(device);
int ret = 0;
unsigned long t;
if (IS_ERR_OR_NULL(rgmu->cx_gdsc))
- return 0;
+ return;
ret = regulator_disable(rgmu->cx_gdsc);
if (ret) {
dev_err(&rgmu->pdev->dev,
"Failed to disable CX gdsc:%d\n", ret);
- return ret;
+ return;
}
/*
@@ -218,17 +218,13 @@ static int rgmu_disable_gdsc(struct kgsl_device *device)
t = jiffies + msecs_to_jiffies(CX_GDSC_TIMEOUT);
do {
if (!regulator_is_enabled(rgmu->cx_gdsc))
- return 0;
+ return;
usleep_range(10, 100);
} while (!(time_after(jiffies, t)));
- if (!regulator_is_enabled(rgmu->cx_gdsc))
- return 0;
-
- dev_err(&rgmu->pdev->dev, "RGMU CX gdsc off timeout\n");
-
- return -ETIMEDOUT;
+ if (regulator_is_enabled(rgmu->cx_gdsc))
+ dev_err(&rgmu->pdev->dev, "RGMU CX gdsc off timeout\n");
}
static int rgmu_enable_gdsc(struct rgmu_device *rgmu)
@@ -404,7 +400,8 @@ static int rgmu_suspend(struct kgsl_device *device)
return -EINVAL;
rgmu_disable_clks(device);
- return rgmu_disable_gdsc(device);
+ rgmu_disable_gdsc(device);
+ return 0;
}
/* To be called to power on both GPU and RGMU */
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 4421e00..0e1c1e4 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -82,6 +82,7 @@
#define HID_DEVICE_ID_ALPS_U1_DUAL_3BTN_PTP 0x1220
#define HID_DEVICE_ID_ALPS_U1 0x1215
#define HID_DEVICE_ID_ALPS_T4_BTNLESS 0x120C
+#define HID_DEVICE_ID_ALPS_1222 0x1222
#define USB_VENDOR_ID_AMI 0x046b
@@ -265,6 +266,7 @@
#define USB_DEVICE_ID_CHICONY_MULTI_TOUCH 0xb19d
#define USB_DEVICE_ID_CHICONY_WIRELESS 0x0618
#define USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE 0x1053
+#define USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE2 0x0939
#define USB_DEVICE_ID_CHICONY_WIRELESS2 0x1123
#define USB_DEVICE_ID_ASUS_AK1D 0x1125
#define USB_DEVICE_ID_CHICONY_ACER_SWITCH12 0x1421
@@ -557,6 +559,7 @@
#define USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A 0x0b4a
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE 0x134a
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A 0x094a
+#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641 0x0641
#define USB_VENDOR_ID_HUION 0x256c
#define USB_DEVICE_ID_HUION_TABLET 0x006e
@@ -1212,6 +1215,7 @@
#define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05
#define USB_DEVICE_ID_PRIMAX_REZEL 0x4e72
#define USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D0F 0x4d0f
+#define USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D65 0x4d65
#define USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4E22 0x4e22
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 184e490..f9167d0 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -1788,6 +1788,10 @@ static const struct hid_device_id mt_devices[] = {
HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
USB_VENDOR_ID_ALPS_JP,
HID_DEVICE_ID_ALPS_U1_DUAL_3BTN_PTP) },
+ { .driver_data = MT_CLS_WIN_8_DUAL,
+ HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
+ USB_VENDOR_ID_ALPS_JP,
+ HID_DEVICE_ID_ALPS_1222) },
/* Lenovo X1 TAB Gen 2 */
{ .driver_data = MT_CLS_WIN_8_DUAL,
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index a9c103c..bbb5733 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -45,6 +45,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM), HID_QUIRK_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE2), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD), HID_QUIRK_BADPAD },
{ HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK), HID_QUIRK_NOGET },
@@ -93,6 +94,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A), HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6680), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_INNOMEDIA, USB_DEVICE_ID_INNEX_GENESIS_ATARI), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X), HID_QUIRK_MULTI_INPUT },
@@ -131,6 +133,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_MOUSE_4D22), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D0F), HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D65), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4E22), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS), HID_QUIRK_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001), HID_QUIRK_NOGET },
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index 0bdd85d..9cd4705 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -275,6 +275,9 @@ static void wacom_feature_mapping(struct hid_device *hdev,
wacom_hid_usage_quirk(hdev, field, usage);
switch (equivalent_usage) {
+ case WACOM_HID_WD_TOUCH_RING_SETTING:
+ wacom->generic_has_leds = true;
+ break;
case HID_DG_CONTACTMAX:
/* leave touch_max as is if predefined */
if (!features->touch_max) {
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index d7c3f4a..e56dc97 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -537,14 +537,14 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
*/
buttons = (data[4] << 1) | (data[3] & 0x01);
} else if (features->type == CINTIQ_COMPANION_2) {
- /* d-pad right -> data[4] & 0x10
- * d-pad up -> data[4] & 0x20
- * d-pad left -> data[4] & 0x40
- * d-pad down -> data[4] & 0x80
- * d-pad center -> data[3] & 0x01
+ /* d-pad right -> data[2] & 0x10
+ * d-pad up -> data[2] & 0x20
+ * d-pad left -> data[2] & 0x40
+ * d-pad down -> data[2] & 0x80
+ * d-pad center -> data[1] & 0x01
*/
buttons = ((data[2] >> 4) << 7) |
- ((data[1] & 0x04) << 6) |
+ ((data[1] & 0x04) << 4) |
((data[2] & 0x0F) << 2) |
(data[1] & 0x03);
} else if (features->type >= INTUOS5S && features->type <= INTUOSPL) {
@@ -1928,8 +1928,6 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev,
features->device_type |= WACOM_DEVICETYPE_PAD;
break;
case WACOM_HID_WD_BUTTONCENTER:
- wacom->generic_has_leds = true;
- /* fall through */
case WACOM_HID_WD_BUTTONHOME:
case WACOM_HID_WD_BUTTONUP:
case WACOM_HID_WD_BUTTONDOWN:
@@ -2121,14 +2119,12 @@ static void wacom_wac_pad_report(struct hid_device *hdev,
bool active = wacom_wac->hid_data.inrange_state != 0;
/* report prox for expresskey events */
- if ((wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY) &&
- wacom_wac->hid_data.pad_input_event_flag) {
+ if (wacom_wac->hid_data.pad_input_event_flag) {
input_event(input, EV_ABS, ABS_MISC, active ? PAD_DEVICE_ID : 0);
input_sync(input);
if (!active)
wacom_wac->hid_data.pad_input_event_flag = false;
}
-
}
static void wacom_wac_pen_usage_mapping(struct hid_device *hdev,
@@ -2725,9 +2721,7 @@ static int wacom_wac_collection(struct hid_device *hdev, struct hid_report *repo
if (report->type != HID_INPUT_REPORT)
return -1;
- if (WACOM_PAD_FIELD(field) && wacom->wacom_wac.pad_input)
- wacom_wac_pad_report(hdev, report, field);
- else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
+ if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input)
wacom_wac_pen_report(hdev, report);
else if (WACOM_FINGER_FIELD(field) && wacom->wacom_wac.touch_input)
wacom_wac_finger_report(hdev, report);
@@ -2741,7 +2735,7 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
struct hid_field *field;
bool pad_in_hid_field = false, pen_in_hid_field = false,
- finger_in_hid_field = false;
+ finger_in_hid_field = false, true_pad = false;
int r;
int prev_collection = -1;
@@ -2757,6 +2751,8 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
pen_in_hid_field = true;
if (WACOM_FINGER_FIELD(field))
finger_in_hid_field = true;
+ if (wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY)
+ true_pad = true;
}
wacom_wac_battery_pre_report(hdev, report);
@@ -2780,6 +2776,9 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
}
wacom_wac_battery_report(hdev, report);
+
+ if (true_pad && wacom->wacom_wac.pad_input)
+ wacom_wac_pad_report(hdev, report, field);
}
static int wacom_bpt_touch(struct wacom_wac *wacom)
@@ -3735,7 +3734,7 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
0, 5920, 4, 0);
}
input_abs_set_res(input_dev, ABS_MT_POSITION_X, 40);
- input_abs_set_res(input_dev, ABS_MT_POSITION_X, 40);
+ input_abs_set_res(input_dev, ABS_MT_POSITION_Y, 40);
/* fall through */
diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h
index 295fd37..f67d871 100644
--- a/drivers/hid/wacom_wac.h
+++ b/drivers/hid/wacom_wac.h
@@ -145,6 +145,7 @@
#define WACOM_HID_WD_OFFSETBOTTOM (WACOM_HID_UP_WACOMDIGITIZER | 0x0d33)
#define WACOM_HID_WD_DATAMODE (WACOM_HID_UP_WACOMDIGITIZER | 0x1002)
#define WACOM_HID_WD_DIGITIZERINFO (WACOM_HID_UP_WACOMDIGITIZER | 0x1013)
+#define WACOM_HID_WD_TOUCH_RING_SETTING (WACOM_HID_UP_WACOMDIGITIZER | 0x1032)
#define WACOM_HID_UP_G9 0xff090000
#define WACOM_HID_G9_PEN (WACOM_HID_UP_G9 | 0x02)
#define WACOM_HID_G9_TOUCHSCREEN (WACOM_HID_UP_G9 | 0x11)
diff --git a/drivers/hwtracing/coresight/coresight-byte-cntr.c b/drivers/hwtracing/coresight/coresight-byte-cntr.c
index 8a0439d..6216417 100644
--- a/drivers/hwtracing/coresight/coresight-byte-cntr.c
+++ b/drivers/hwtracing/coresight/coresight-byte-cntr.c
@@ -17,6 +17,7 @@
#include "coresight-tmc.h"
#define USB_BLK_SIZE 65536
+#define USB_SG_NUM (USB_BLK_SIZE / PAGE_SIZE)
#define USB_BUF_NUM 255
static struct tmc_drvdata *tmcdrvdata;
@@ -315,10 +316,11 @@ static int byte_cntr_register_chardev(struct byte_cntr *byte_cntr_data)
static void usb_read_work_fn(struct work_struct *work)
{
- int ret, seq = 0;
+ int ret, i, seq = 0;
struct qdss_request *usb_req = NULL;
struct etr_buf *etr_buf = tmcdrvdata->etr_buf;
size_t actual, req_size;
+ char *buf;
struct byte_cntr *drvdata =
container_of(work, struct byte_cntr, read_work);
@@ -337,50 +339,65 @@ static void usb_read_work_fn(struct work_struct *work)
}
req_size = USB_BLK_SIZE;
- while (req_size > 0) {
- seq++;
- usb_req = kzalloc(sizeof(*usb_req), GFP_KERNEL);
- if (!usb_req)
- return;
+ seq++;
+ usb_req = devm_kzalloc(tmcdrvdata->dev, sizeof(*usb_req),
+ GFP_KERNEL);
+ if (!usb_req)
+ return;
+ usb_req->sg = devm_kzalloc(tmcdrvdata->dev,
+ sizeof(*(usb_req->sg)) * USB_SG_NUM, GFP_KERNEL);
+ if (!usb_req->sg) {
+ devm_kfree(tmcdrvdata->dev, usb_req->sg);
+ return;
+ }
+ usb_req->length = USB_BLK_SIZE;
+ drvdata->usb_req = usb_req;
+ for (i = 0; i < USB_SG_NUM; i++) {
actual = tmc_etr_buf_get_data(etr_buf, drvdata->offset,
- req_size, &usb_req->buf);
+ PAGE_SIZE, &buf);
if (actual <= 0) {
- kfree(usb_req);
+ devm_kfree(tmcdrvdata->dev, usb_req->sg);
+ devm_kfree(tmcdrvdata->dev, usb_req);
usb_req = NULL;
dev_err(tmcdrvdata->dev, "No data in ETR\n");
- break;
+ return;
}
- usb_req->length = actual;
- drvdata->usb_req = usb_req;
+ sg_set_buf(&usb_req->sg[i], buf, actual);
+ if (i == 0)
+ usb_req->buf = buf;
req_size -= actual;
- if ((drvdata->offset + usb_req->length)
- >= tmcdrvdata->size)
+ if ((drvdata->offset + actual) >= tmcdrvdata->size)
drvdata->offset = 0;
else
- drvdata->offset += usb_req->length;
- if (atomic_read(&drvdata->usb_free_buf) > 0) {
- ret = usb_qdss_write(tmcdrvdata->usbch,
- drvdata->usb_req);
- if (ret) {
- kfree(usb_req);
- usb_req = NULL;
- drvdata->usb_req = NULL;
- dev_err(tmcdrvdata->dev,
- "Write data failed:%d\n", ret);
- if (ret == -EAGAIN)
- continue;
- return;
- }
- atomic_dec(&drvdata->usb_free_buf);
-
- } else {
- dev_dbg(tmcdrvdata->dev,
- "Drop data, offset = %d, seq = %d, irq = %d\n",
- drvdata->offset, seq,
- atomic_read(&drvdata->irq_cnt));
- kfree(usb_req);
+ drvdata->offset += actual;
+ if (i == USB_SG_NUM - 1)
+ sg_mark_end(&usb_req->sg[i]);
+ }
+ usb_req->num_sgs = i;
+ if (atomic_read(&drvdata->usb_free_buf) > 0) {
+ ret = usb_qdss_write(tmcdrvdata->usbch,
+ drvdata->usb_req);
+ if (ret) {
+ devm_kfree(tmcdrvdata->dev, usb_req->sg);
+ devm_kfree(tmcdrvdata->dev, usb_req);
+ usb_req = NULL;
drvdata->usb_req = NULL;
+ dev_err(tmcdrvdata->dev,
+ "Write data failed:%d\n", ret);
+ if (ret == -EAGAIN)
+ continue;
+ return;
}
+ atomic_dec(&drvdata->usb_free_buf);
+
+ } else {
+ dev_dbg(tmcdrvdata->dev,
+ "Drop data, offset = %d, seq = %d, irq = %d\n",
+ drvdata->offset, seq,
+ atomic_read(&drvdata->irq_cnt));
+ devm_kfree(tmcdrvdata->dev, usb_req->sg);
+ devm_kfree(tmcdrvdata->dev, usb_req);
+ drvdata->usb_req = NULL;
}
if (atomic_read(&drvdata->irq_cnt) > 0)
atomic_dec(&drvdata->irq_cnt);
@@ -394,7 +411,8 @@ static void usb_write_done(struct byte_cntr *drvdata,
atomic_inc(&drvdata->usb_free_buf);
if (d_req->status)
pr_err_ratelimited("USB write failed err:%d\n", d_req->status);
- kfree(d_req);
+ devm_kfree(tmcdrvdata->dev, d_req->sg);
+ devm_kfree(tmcdrvdata->dev, d_req);
}
void usb_bypass_notifier(void *priv, unsigned int event,
diff --git a/drivers/hwtracing/intel_th/msu.c b/drivers/hwtracing/intel_th/msu.c
index 8ff326c..3cdf85b 100644
--- a/drivers/hwtracing/intel_th/msu.c
+++ b/drivers/hwtracing/intel_th/msu.c
@@ -632,7 +632,7 @@ static int msc_buffer_contig_alloc(struct msc *msc, unsigned long size)
goto err_out;
ret = -ENOMEM;
- page = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
+ page = alloc_pages(GFP_KERNEL | __GFP_ZERO | GFP_DMA32, order);
if (!page)
goto err_free_sgt;
diff --git a/drivers/hwtracing/intel_th/pci.c b/drivers/hwtracing/intel_th/pci.c
index 70f2cb9..e759ac0 100644
--- a/drivers/hwtracing/intel_th/pci.c
+++ b/drivers/hwtracing/intel_th/pci.c
@@ -170,6 +170,11 @@ static const struct pci_device_id intel_th_pci_id_table[] = {
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x02a6),
.driver_data = (kernel_ulong_t)&intel_th_2x,
},
+ {
+ /* Ice Lake NNPI */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x45c5),
+ .driver_data = (kernel_ulong_t)&intel_th_2x,
+ },
{ 0 },
};
diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c
index a492da9..ac9c948 100644
--- a/drivers/i2c/busses/i2c-stm32f7.c
+++ b/drivers/i2c/busses/i2c-stm32f7.c
@@ -24,7 +24,6 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
@@ -1782,15 +1781,14 @@ static struct i2c_algorithm stm32f7_i2c_algo = {
static int stm32f7_i2c_probe(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node;
struct stm32f7_i2c_dev *i2c_dev;
const struct stm32f7_i2c_setup *setup;
struct resource *res;
- u32 irq_error, irq_event, clk_rate, rise_time, fall_time;
+ u32 clk_rate, rise_time, fall_time;
struct i2c_adapter *adap;
struct reset_control *rst;
dma_addr_t phy_addr;
- int ret;
+ int irq_error, irq_event, ret;
i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
if (!i2c_dev)
@@ -1802,16 +1800,20 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
return PTR_ERR(i2c_dev->base);
phy_addr = (dma_addr_t)res->start;
- irq_event = irq_of_parse_and_map(np, 0);
- if (!irq_event) {
- dev_err(&pdev->dev, "IRQ event missing or invalid\n");
- return -EINVAL;
+ irq_event = platform_get_irq(pdev, 0);
+ if (irq_event <= 0) {
+ if (irq_event != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Failed to get IRQ event: %d\n",
+ irq_event);
+ return irq_event ? : -ENOENT;
}
- irq_error = irq_of_parse_and_map(np, 1);
- if (!irq_error) {
- dev_err(&pdev->dev, "IRQ error missing or invalid\n");
- return -EINVAL;
+ irq_error = platform_get_irq(pdev, 1);
+ if (irq_error <= 0) {
+ if (irq_error != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Failed to get IRQ error: %d\n",
+ irq_error);
+ return irq_error ? : -ENOENT;
}
i2c_dev->clk = devm_clk_get(&pdev->dev, NULL);
diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index 5b0e1d9..1de10e5 100644
--- a/drivers/i2c/i2c-core-base.c
+++ b/drivers/i2c/i2c-core-base.c
@@ -185,7 +185,7 @@ static int i2c_generic_bus_free(struct i2c_adapter *adap)
int i2c_generic_scl_recovery(struct i2c_adapter *adap)
{
struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
- int i = 0, scl = 1, ret;
+ int i = 0, scl = 1, ret = 0;
if (bri->prepare_recovery)
bri->prepare_recovery(adap);
diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c
index fcd4a1c..15a1152 100644
--- a/drivers/iio/adc/stm32-dfsdm-adc.c
+++ b/drivers/iio/adc/stm32-dfsdm-adc.c
@@ -1144,6 +1144,12 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev)
* So IRQ associated to filter instance 0 is dedicated to the Filter 0.
*/
irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ if (irq != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get IRQ: %d\n", irq);
+ return irq;
+ }
+
ret = devm_request_irq(dev, irq, stm32_dfsdm_irq,
0, pdev->name, adc);
if (ret < 0) {
diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c
index bf089f5..9416306 100644
--- a/drivers/iio/adc/stm32-dfsdm-core.c
+++ b/drivers/iio/adc/stm32-dfsdm-core.c
@@ -213,6 +213,8 @@ static int stm32_dfsdm_parse_of(struct platform_device *pdev,
}
priv->dfsdm.phys_base = res->start;
priv->dfsdm.base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->dfsdm.base))
+ return PTR_ERR(priv->dfsdm.base);
/*
* "dfsdm" clock is mandatory for DFSDM peripheral clocking.
@@ -222,8 +224,10 @@ static int stm32_dfsdm_parse_of(struct platform_device *pdev,
*/
priv->clk = devm_clk_get(&pdev->dev, "dfsdm");
if (IS_ERR(priv->clk)) {
- dev_err(&pdev->dev, "No stm32_dfsdm_clk clock found\n");
- return -EINVAL;
+ ret = PTR_ERR(priv->clk);
+ if (ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Failed to get clock (%d)\n", ret);
+ return ret;
}
priv->aclk = devm_clk_get(&pdev->dev, "audio");
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index 7b794a1..8be082e 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -1232,7 +1232,6 @@ static int roce_resolve_route_from_path(struct sa_path_rec *rec,
{
struct rdma_dev_addr dev_addr = {};
union {
- struct sockaddr _sockaddr;
struct sockaddr_in _sockaddr_in;
struct sockaddr_in6 _sockaddr_in6;
} sgid_addr, dgid_addr;
@@ -1249,12 +1248,12 @@ static int roce_resolve_route_from_path(struct sa_path_rec *rec,
*/
dev_addr.net = &init_net;
- rdma_gid2ip(&sgid_addr._sockaddr, &rec->sgid);
- rdma_gid2ip(&dgid_addr._sockaddr, &rec->dgid);
+ rdma_gid2ip((struct sockaddr *)&sgid_addr, &rec->sgid);
+ rdma_gid2ip((struct sockaddr *)&dgid_addr, &rec->dgid);
/* validate the route */
- ret = rdma_resolve_ip_route(&sgid_addr._sockaddr,
- &dgid_addr._sockaddr, &dev_addr);
+ ret = rdma_resolve_ip_route((struct sockaddr *)&sgid_addr,
+ (struct sockaddr *)&dgid_addr, &dev_addr);
if (ret)
return ret;
diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c
index d8eb4dc..6aa5a8a 100644
--- a/drivers/infiniband/hw/hfi1/chip.c
+++ b/drivers/infiniband/hw/hfi1/chip.c
@@ -14586,7 +14586,7 @@ void hfi1_deinit_vnic_rsm(struct hfi1_devdata *dd)
clear_rcvctrl(dd, RCV_CTRL_RCV_RSM_ENABLE_SMASK);
}
-static void init_rxe(struct hfi1_devdata *dd)
+static int init_rxe(struct hfi1_devdata *dd)
{
struct rsm_map_table *rmt;
u64 val;
@@ -14595,6 +14595,9 @@ static void init_rxe(struct hfi1_devdata *dd)
write_csr(dd, RCV_ERR_MASK, ~0ull);
rmt = alloc_rsm_map_table(dd);
+ if (!rmt)
+ return -ENOMEM;
+
/* set up QOS, including the QPN map table */
init_qos(dd, rmt);
init_user_fecn_handling(dd, rmt);
@@ -14621,6 +14624,7 @@ static void init_rxe(struct hfi1_devdata *dd)
val |= ((4ull & RCV_BYPASS_HDR_SIZE_MASK) <<
RCV_BYPASS_HDR_SIZE_SHIFT);
write_csr(dd, RCV_BYPASS, val);
+ return 0;
}
static void init_other(struct hfi1_devdata *dd)
@@ -15163,7 +15167,10 @@ struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev,
goto bail_cleanup;
/* set initial RXE CSRs */
- init_rxe(dd);
+ ret = init_rxe(dd);
+ if (ret)
+ goto bail_cleanup;
+
/* set initial TXE CSRs */
init_txe(dd);
/* set initial non-RXE, non-TXE CSRs */
diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c
index 27d9c4c..1ad38c8 100644
--- a/drivers/infiniband/hw/hfi1/verbs.c
+++ b/drivers/infiniband/hw/hfi1/verbs.c
@@ -54,6 +54,7 @@
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <rdma/opa_addr.h>
+#include <linux/nospec.h>
#include "hfi.h"
#include "common.h"
@@ -1596,6 +1597,7 @@ static int hfi1_check_ah(struct ib_device *ibdev, struct rdma_ah_attr *ah_attr)
sl = rdma_ah_get_sl(ah_attr);
if (sl >= ARRAY_SIZE(ibp->sl_to_sc))
return -EINVAL;
+ sl = array_index_nospec(sl, ARRAY_SIZE(ibp->sl_to_sc));
sc5 = ibp->sl_to_sc[sl];
if (sc_to_vlt(dd, sc5) > num_vls && sc_to_vlt(dd, sc5) != 0xf)
diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c
index e2e6c74..a5e3349 100644
--- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c
+++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c
@@ -806,6 +806,8 @@ static int i40iw_query_qp(struct ib_qp *ibqp,
struct i40iw_qp *iwqp = to_iwqp(ibqp);
struct i40iw_sc_qp *qp = &iwqp->sc_qp;
+ attr->qp_state = iwqp->ibqp_state;
+ attr->cur_qp_state = attr->qp_state;
attr->qp_access_flags = 0;
attr->cap.max_send_wr = qp->qp_uk.sq_size;
attr->cap.max_recv_wr = qp->qp_uk.rq_size;
diff --git a/drivers/infiniband/hw/mlx5/mad.c b/drivers/infiniband/hw/mlx5/mad.c
index 32a9e92..cdf6e26 100644
--- a/drivers/infiniband/hw/mlx5/mad.c
+++ b/drivers/infiniband/hw/mlx5/mad.c
@@ -197,19 +197,33 @@ static void pma_cnt_assign(struct ib_pma_portcounters *pma_cnt,
vl_15_dropped);
}
-static int process_pma_cmd(struct mlx5_core_dev *mdev, u8 port_num,
+static int process_pma_cmd(struct mlx5_ib_dev *dev, u8 port_num,
const struct ib_mad *in_mad, struct ib_mad *out_mad)
{
- int err;
+ struct mlx5_core_dev *mdev;
+ bool native_port = true;
+ u8 mdev_port_num;
void *out_cnt;
+ int err;
+ mdev = mlx5_ib_get_native_port_mdev(dev, port_num, &mdev_port_num);
+ if (!mdev) {
+ /* Fail to get the native port, likely due to 2nd port is still
+ * unaffiliated. In such case default to 1st port and attached
+ * PF device.
+ */
+ native_port = false;
+ mdev = dev->mdev;
+ mdev_port_num = 1;
+ }
/* Declaring support of extended counters */
if (in_mad->mad_hdr.attr_id == IB_PMA_CLASS_PORT_INFO) {
struct ib_class_port_info cpi = {};
cpi.capability_mask = IB_PMA_CLASS_CAP_EXT_WIDTH;
memcpy((out_mad->data + 40), &cpi, sizeof(cpi));
- return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
+ err = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
+ goto done;
}
if (in_mad->mad_hdr.attr_id == IB_PMA_PORT_COUNTERS_EXT) {
@@ -218,11 +232,13 @@ static int process_pma_cmd(struct mlx5_core_dev *mdev, u8 port_num,
int sz = MLX5_ST_SZ_BYTES(query_vport_counter_out);
out_cnt = kvzalloc(sz, GFP_KERNEL);
- if (!out_cnt)
- return IB_MAD_RESULT_FAILURE;
+ if (!out_cnt) {
+ err = IB_MAD_RESULT_FAILURE;
+ goto done;
+ }
err = mlx5_core_query_vport_counter(mdev, 0, 0,
- port_num, out_cnt, sz);
+ mdev_port_num, out_cnt, sz);
if (!err)
pma_cnt_ext_assign(pma_cnt_ext, out_cnt);
} else {
@@ -231,20 +247,23 @@ static int process_pma_cmd(struct mlx5_core_dev *mdev, u8 port_num,
int sz = MLX5_ST_SZ_BYTES(ppcnt_reg);
out_cnt = kvzalloc(sz, GFP_KERNEL);
- if (!out_cnt)
- return IB_MAD_RESULT_FAILURE;
+ if (!out_cnt) {
+ err = IB_MAD_RESULT_FAILURE;
+ goto done;
+ }
- err = mlx5_core_query_ib_ppcnt(mdev, port_num,
+ err = mlx5_core_query_ib_ppcnt(mdev, mdev_port_num,
out_cnt, sz);
if (!err)
pma_cnt_assign(pma_cnt, out_cnt);
- }
-
+ }
kvfree(out_cnt);
- if (err)
- return IB_MAD_RESULT_FAILURE;
-
- return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
+ err = err ? IB_MAD_RESULT_FAILURE :
+ IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
+done:
+ if (native_port)
+ mlx5_ib_put_native_port_mdev(dev, port_num);
+ return err;
}
int mlx5_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
@@ -256,8 +275,6 @@ int mlx5_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
struct mlx5_ib_dev *dev = to_mdev(ibdev);
const struct ib_mad *in_mad = (const struct ib_mad *)in;
struct ib_mad *out_mad = (struct ib_mad *)out;
- struct mlx5_core_dev *mdev;
- u8 mdev_port_num;
int ret;
if (WARN_ON_ONCE(in_mad_size != sizeof(*in_mad) ||
@@ -266,19 +283,14 @@ int mlx5_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
memset(out_mad->data, 0, sizeof(out_mad->data));
- mdev = mlx5_ib_get_native_port_mdev(dev, port_num, &mdev_port_num);
- if (!mdev)
- return IB_MAD_RESULT_FAILURE;
-
- if (MLX5_CAP_GEN(mdev, vport_counters) &&
+ if (MLX5_CAP_GEN(dev->mdev, vport_counters) &&
in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT &&
in_mad->mad_hdr.method == IB_MGMT_METHOD_GET) {
- ret = process_pma_cmd(mdev, mdev_port_num, in_mad, out_mad);
+ ret = process_pma_cmd(dev, port_num, in_mad, out_mad);
} else {
ret = process_mad(ibdev, mad_flags, port_num, in_wc, in_grh,
in_mad, out_mad);
}
- mlx5_ib_put_native_port_mdev(dev, port_num);
return ret;
}
diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
index 8cc4da6..53eccc0d 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -939,15 +939,19 @@ static int mlx5_ib_query_device(struct ib_device *ibdev,
}
if (MLX5_CAP_GEN(mdev, tag_matching)) {
- props->tm_caps.max_rndv_hdr_size = MLX5_TM_MAX_RNDV_MSG_SIZE;
props->tm_caps.max_num_tags =
(1 << MLX5_CAP_GEN(mdev, log_tag_matching_list_sz)) - 1;
- props->tm_caps.flags = IB_TM_CAP_RC;
props->tm_caps.max_ops =
1 << MLX5_CAP_GEN(mdev, log_max_qp_sz);
props->tm_caps.max_sge = MLX5_TM_MAX_SGE;
}
+ if (MLX5_CAP_GEN(mdev, tag_matching) &&
+ MLX5_CAP_GEN(mdev, rndv_offload_rc)) {
+ props->tm_caps.flags = IB_TM_CAP_RNDV_RC;
+ props->tm_caps.max_rndv_hdr_size = MLX5_TM_MAX_RNDV_MSG_SIZE;
+ }
+
if (MLX5_CAP_GEN(dev->mdev, cq_moderation)) {
props->cq_caps.max_cq_moderation_count =
MLX5_MAX_CQ_COUNT;
diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h
index 320d4df..941d1df 100644
--- a/drivers/infiniband/hw/mlx5/mlx5_ib.h
+++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h
@@ -467,6 +467,7 @@ struct mlx5_umr_wr {
u64 length;
int access_flags;
u32 mkey;
+ u8 ignore_free_state:1;
};
static inline const struct mlx5_umr_wr *umr_wr(const struct ib_send_wr *wr)
diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c
index 7df4a4f..9bab4fb 100644
--- a/drivers/infiniband/hw/mlx5/mr.c
+++ b/drivers/infiniband/hw/mlx5/mr.c
@@ -548,14 +548,17 @@ void mlx5_mr_cache_free(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
return;
c = order2idx(dev, mr->order);
- if (c < 0 || c >= MAX_MR_CACHE_ENTRIES) {
- mlx5_ib_warn(dev, "order %d, cache index %d\n", mr->order, c);
+ WARN_ON(c < 0 || c >= MAX_MR_CACHE_ENTRIES);
+
+ if (unreg_umr(dev, mr)) {
+ mr->allocated_from_cache = false;
+ destroy_mkey(dev, mr);
+ ent = &cache->ent[c];
+ if (ent->cur < ent->limit)
+ queue_work(cache->wq, &ent->work);
return;
}
- if (unreg_umr(dev, mr))
- return;
-
ent = &cache->ent[c];
spin_lock_irq(&ent->lock);
list_add_tail(&mr->list, &ent->head);
@@ -1408,9 +1411,11 @@ static int unreg_umr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
return 0;
umrwr.wr.send_flags = MLX5_IB_SEND_UMR_DISABLE_MR |
- MLX5_IB_SEND_UMR_FAIL_IF_FREE;
+ MLX5_IB_SEND_UMR_UPDATE_PD_ACCESS;
umrwr.wr.opcode = MLX5_IB_WR_UMR;
+ umrwr.pd = dev->umrc.pd;
umrwr.mkey = mr->mmkey.key;
+ umrwr.ignore_free_state = 1;
return mlx5_ib_post_send_wait(dev, &umrwr);
}
@@ -1615,10 +1620,10 @@ static void clean_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
mr->sig = NULL;
}
- mlx5_free_priv_descs(mr);
-
- if (!allocated_from_cache)
+ if (!allocated_from_cache) {
destroy_mkey(dev, mr);
+ mlx5_free_priv_descs(mr);
+ }
}
static void dereg_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c
index 183fe5c..77b1f3f 100644
--- a/drivers/infiniband/hw/mlx5/qp.c
+++ b/drivers/infiniband/hw/mlx5/qp.c
@@ -1501,7 +1501,6 @@ static int create_rss_raw_qp_tir(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
}
MLX5_SET(tirc, tirc, rx_hash_fn, MLX5_RX_HASH_FN_TOEPLITZ);
- MLX5_SET(tirc, tirc, rx_hash_symmetric, 1);
memcpy(rss_key, ucmd.rx_hash_key, len);
break;
}
@@ -3717,10 +3716,14 @@ static int set_reg_umr_segment(struct mlx5_ib_dev *dev,
memset(umr, 0, sizeof(*umr));
- if (wr->send_flags & MLX5_IB_SEND_UMR_FAIL_IF_FREE)
- umr->flags = MLX5_UMR_CHECK_FREE; /* fail if free */
- else
- umr->flags = MLX5_UMR_CHECK_NOT_FREE; /* fail if not free */
+ if (!umrwr->ignore_free_state) {
+ if (wr->send_flags & MLX5_IB_SEND_UMR_FAIL_IF_FREE)
+ /* fail if free */
+ umr->flags = MLX5_UMR_CHECK_FREE;
+ else
+ /* fail if not free */
+ umr->flags = MLX5_UMR_CHECK_NOT_FREE;
+ }
umr->xlt_octowords = cpu_to_be16(get_xlt_octo(umrwr->xlt_size));
if (wr->send_flags & MLX5_IB_SEND_UMR_UPDATE_XLT) {
diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c
index 4111b79..681d8e0 100644
--- a/drivers/infiniband/sw/rxe/rxe_resp.c
+++ b/drivers/infiniband/sw/rxe/rxe_resp.c
@@ -435,6 +435,7 @@ static enum resp_states check_rkey(struct rxe_qp *qp,
qp->resp.va = reth_va(pkt);
qp->resp.rkey = reth_rkey(pkt);
qp->resp.resid = reth_len(pkt);
+ qp->resp.length = reth_len(pkt);
}
access = (pkt->mask & RXE_READ_MASK) ? IB_ACCESS_REMOTE_READ
: IB_ACCESS_REMOTE_WRITE;
@@ -859,7 +860,9 @@ static enum resp_states do_complete(struct rxe_qp *qp,
pkt->mask & RXE_WRITE_MASK) ?
IB_WC_RECV_RDMA_WITH_IMM : IB_WC_RECV;
wc->vendor_err = 0;
- wc->byte_len = wqe->dma.length - wqe->dma.resid;
+ wc->byte_len = (pkt->mask & RXE_IMMDT_MASK &&
+ pkt->mask & RXE_WRITE_MASK) ?
+ qp->resp.length : wqe->dma.length - wqe->dma.resid;
/* fields after byte_len are different between kernel and user
* space
diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.h b/drivers/infiniband/sw/rxe/rxe_verbs.h
index 332a16da..3b731c7 100644
--- a/drivers/infiniband/sw/rxe/rxe_verbs.h
+++ b/drivers/infiniband/sw/rxe/rxe_verbs.h
@@ -212,6 +212,7 @@ struct rxe_resp_info {
struct rxe_mem *mr;
u32 resid;
u32 rkey;
+ u32 length;
u64 atomic_orig;
/* SRQ only */
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 30f840f..78dd36d 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -1892,12 +1892,6 @@ static void ipoib_child_init(struct net_device *ndev)
struct ipoib_dev_priv *priv = ipoib_priv(ndev);
struct ipoib_dev_priv *ppriv = ipoib_priv(priv->parent);
- dev_hold(priv->parent);
-
- down_write(&ppriv->vlan_rwsem);
- list_add_tail(&priv->list, &ppriv->child_intfs);
- up_write(&ppriv->vlan_rwsem);
-
priv->max_ib_mtu = ppriv->max_ib_mtu;
set_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags);
memcpy(priv->dev->dev_addr, ppriv->dev->dev_addr, INFINIBAND_ALEN);
@@ -1940,6 +1934,17 @@ static int ipoib_ndo_init(struct net_device *ndev)
if (rc) {
pr_warn("%s: failed to initialize device: %s port %d (ret = %d)\n",
priv->ca->name, priv->dev->name, priv->port, rc);
+ return rc;
+ }
+
+ if (priv->parent) {
+ struct ipoib_dev_priv *ppriv = ipoib_priv(priv->parent);
+
+ dev_hold(priv->parent);
+
+ down_write(&ppriv->vlan_rwsem);
+ list_add_tail(&priv->list, &ppriv->child_intfs);
+ up_write(&ppriv->vlan_rwsem);
}
return 0;
@@ -1957,6 +1962,14 @@ static void ipoib_ndo_uninit(struct net_device *dev)
*/
WARN_ON(!list_empty(&priv->child_intfs));
+ if (priv->parent) {
+ struct ipoib_dev_priv *ppriv = ipoib_priv(priv->parent);
+
+ down_write(&ppriv->vlan_rwsem);
+ list_del(&priv->list);
+ up_write(&ppriv->vlan_rwsem);
+ }
+
ipoib_neigh_hash_uninit(dev);
ipoib_ib_dev_cleanup(dev);
@@ -1968,15 +1981,8 @@ static void ipoib_ndo_uninit(struct net_device *dev)
priv->wq = NULL;
}
- if (priv->parent) {
- struct ipoib_dev_priv *ppriv = ipoib_priv(priv->parent);
-
- down_write(&ppriv->vlan_rwsem);
- list_del(&priv->list);
- up_write(&ppriv->vlan_rwsem);
-
+ if (priv->parent)
dev_put(priv->parent);
- }
}
static int ipoib_set_vf_link_state(struct net_device *dev, int vf, int link_state)
@@ -1997,6 +2003,7 @@ static int ipoib_get_vf_config(struct net_device *dev, int vf,
return err;
ivf->vf = vf;
+ memcpy(ivf->mac, dev->dev_addr, dev->addr_len);
return 0;
}
diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c
index 539cb67..ae9c51c 100644
--- a/drivers/input/keyboard/imx_keypad.c
+++ b/drivers/input/keyboard/imx_keypad.c
@@ -526,11 +526,12 @@ static int imx_keypad_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused imx_kbd_suspend(struct device *dev)
+static int __maybe_unused imx_kbd_noirq_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx_keypad *kbd = platform_get_drvdata(pdev);
struct input_dev *input_dev = kbd->input_dev;
+ unsigned short reg_val = readw(kbd->mmio_base + KPSR);
/* imx kbd can wake up system even clock is disabled */
mutex_lock(&input_dev->mutex);
@@ -540,13 +541,20 @@ static int __maybe_unused imx_kbd_suspend(struct device *dev)
mutex_unlock(&input_dev->mutex);
- if (device_may_wakeup(&pdev->dev))
+ if (device_may_wakeup(&pdev->dev)) {
+ if (reg_val & KBD_STAT_KPKD)
+ reg_val |= KBD_STAT_KRIE;
+ if (reg_val & KBD_STAT_KPKR)
+ reg_val |= KBD_STAT_KDIE;
+ writew(reg_val, kbd->mmio_base + KPSR);
+
enable_irq_wake(kbd->irq);
+ }
return 0;
}
-static int __maybe_unused imx_kbd_resume(struct device *dev)
+static int __maybe_unused imx_kbd_noirq_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx_keypad *kbd = platform_get_drvdata(pdev);
@@ -570,7 +578,9 @@ static int __maybe_unused imx_kbd_resume(struct device *dev)
return ret;
}
-static SIMPLE_DEV_PM_OPS(imx_kbd_pm_ops, imx_kbd_suspend, imx_kbd_resume);
+static const struct dev_pm_ops imx_kbd_pm_ops = {
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_kbd_noirq_suspend, imx_kbd_noirq_resume)
+};
static struct platform_driver imx_keypad_driver = {
.driver = {
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 0a6f7ca..dd80ff6 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -24,6 +24,7 @@
#include "psmouse.h"
#include "alps.h"
+#include "trackpoint.h"
/*
* Definitions for ALPS version 3 and 4 command mode protocol
@@ -2864,6 +2865,23 @@ static const struct alps_protocol_info *alps_match_table(unsigned char *e7,
return NULL;
}
+static bool alps_is_cs19_trackpoint(struct psmouse *psmouse)
+{
+ u8 param[2] = { 0 };
+
+ if (ps2_command(&psmouse->ps2dev,
+ param, MAKE_PS2_CMD(0, 2, TP_READ_ID)))
+ return false;
+
+ /*
+ * param[0] contains the trackpoint device variant_id while
+ * param[1] contains the firmware_id. So far all alps
+ * trackpoint-only devices have their variant_ids equal
+ * TP_VARIANT_ALPS and their firmware_ids are in 0x20~0x2f range.
+ */
+ return param[0] == TP_VARIANT_ALPS && ((param[1] & 0xf0) == 0x20);
+}
+
static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
{
const struct alps_protocol_info *protocol;
@@ -3165,6 +3183,20 @@ int alps_detect(struct psmouse *psmouse, bool set_properties)
return error;
/*
+ * ALPS cs19 is a trackpoint-only device, and uses different
+ * protocol than DualPoint ones, so we return -EINVAL here and let
+ * trackpoint.c drive this device. If the trackpoint driver is not
+ * enabled, the device will fall back to a bare PS/2 mouse.
+ * If ps2_command() fails here, we depend on the immediately
+ * followed psmouse_reset() to reset the device to normal state.
+ */
+ if (alps_is_cs19_trackpoint(psmouse)) {
+ psmouse_dbg(psmouse,
+ "ALPS CS19 trackpoint-only device detected, ignoring\n");
+ return -EINVAL;
+ }
+
+ /*
* Reset the device to make sure it is fully operational:
* on some laptops, like certain Dell Latitudes, we may
* fail to properly detect presence of trackstick if device
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index a7f8b16..530142b 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -1189,6 +1189,8 @@ static const char * const middle_button_pnp_ids[] = {
"LEN2132", /* ThinkPad P52 */
"LEN2133", /* ThinkPad P72 w/ NFC */
"LEN2134", /* ThinkPad P72 */
+ "LEN0407",
+ "LEN0408",
NULL
};
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 8e6077d..af7d484 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -176,8 +176,10 @@ static const char * const smbus_pnp_ids[] = {
"LEN0072", /* X1 Carbon Gen 5 (2017) - Elan/ALPS trackpoint */
"LEN0073", /* X1 Carbon G5 (Elantech) */
"LEN0092", /* X1 Carbon 6 */
+ "LEN0093", /* T480 */
"LEN0096", /* X280 */
"LEN0097", /* X280 -> ALPS trackpoint */
+ "LEN009b", /* T580 */
"LEN200f", /* T450s */
"LEN2054", /* E480 */
"LEN2055", /* E580 */
diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c
index 4b8b9d7..3503122 100644
--- a/drivers/input/tablet/gtco.c
+++ b/drivers/input/tablet/gtco.c
@@ -78,6 +78,7 @@ Scott Hill shill@gtcocalcomp.com
/* Max size of a single report */
#define REPORT_MAX_SIZE 10
+#define MAX_COLLECTION_LEVELS 10
/* Bitmask whether pen is in range */
@@ -223,8 +224,7 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
char maintype = 'x';
char globtype[12];
int indent = 0;
- char indentstr[10] = "";
-
+ char indentstr[MAX_COLLECTION_LEVELS + 1] = { 0 };
dev_dbg(ddev, "======>>>>>>PARSE<<<<<<======\n");
@@ -350,6 +350,13 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
case TAG_MAIN_COL_START:
maintype = 'S';
+ if (indent == MAX_COLLECTION_LEVELS) {
+ dev_err(ddev, "Collection level %d would exceed limit of %d\n",
+ indent + 1,
+ MAX_COLLECTION_LEVELS);
+ break;
+ }
+
if (data == 0) {
dev_dbg(ddev, "======>>>>>> Physical\n");
strcpy(globtype, "Physical");
@@ -369,8 +376,15 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
break;
case TAG_MAIN_COL_END:
- dev_dbg(ddev, "<<<<<<======\n");
maintype = 'E';
+
+ if (indent == 0) {
+ dev_err(ddev, "Collection level already at zero\n");
+ break;
+ }
+
+ dev_dbg(ddev, "<<<<<<======\n");
+
indent--;
for (x = 0; x < indent; x++)
indentstr[x] = '-';
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 8ced186..fb793de 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -1147,21 +1147,44 @@ static void arm_smmu_tlb_sync_global(struct arm_smmu_device *smmu)
spin_unlock_irqrestore(&smmu->global_sync_lock, flags);
}
+static void arm_smmu_tlb_inv_context_s1(void *cookie);
+
static void arm_smmu_tlb_sync_context(void *cookie)
{
struct arm_smmu_domain *smmu_domain = cookie;
struct arm_smmu_device *smmu = smmu_domain->smmu;
+ struct device *dev = smmu_domain->dev;
+ struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
void __iomem *base = ARM_SMMU_CB(smmu, smmu_domain->cfg.cbndx);
unsigned long flags;
+ size_t ret;
+ bool use_tlbiall = smmu->options & ARM_SMMU_OPT_NO_ASID_RETENTION;
+ ktime_t cur = ktime_get();
+
+ ret = arm_smmu_domain_power_on(&smmu_domain->domain,
+ smmu_domain->smmu);
+ if (ret)
+ return;
+
+ trace_tlbi_start(dev, 0);
+
+ if (!use_tlbiall)
+ writel_relaxed(cfg->asid, base + ARM_SMMU_CB_S1_TLBIASID);
+ else
+ writel_relaxed(0, base + ARM_SMMU_CB_S1_TLBIALL);
spin_lock_irqsave(&smmu_domain->sync_lock, flags);
if (__arm_smmu_tlb_sync(smmu, base + ARM_SMMU_CB_TLBSYNC,
- base + ARM_SMMU_CB_TLBSTATUS))
+ base + ARM_SMMU_CB_TLBSTATUS))
dev_err_ratelimited(smmu->dev,
- "TLB sync on cb%d failed for device %s\n",
- smmu_domain->cfg.cbndx,
- dev_name(smmu_domain->dev));
+ "TLB sync on cb%d failed for device %s\n",
+ smmu_domain->cfg.cbndx,
+ dev_name(smmu_domain->dev));
spin_unlock_irqrestore(&smmu_domain->sync_lock, flags);
+
+ trace_tlbi_end(dev, ktime_us_delta(ktime_get(), cur));
+
+ arm_smmu_domain_power_off(&smmu_domain->domain, smmu_domain->smmu);
}
static void arm_smmu_tlb_sync_vmid(void *cookie)
@@ -1173,23 +1196,7 @@ static void arm_smmu_tlb_sync_vmid(void *cookie)
static void arm_smmu_tlb_inv_context_s1(void *cookie)
{
- struct arm_smmu_domain *smmu_domain = cookie;
- struct device *dev = smmu_domain->dev;
- struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
- struct arm_smmu_device *smmu = smmu_domain->smmu;
- void __iomem *base = ARM_SMMU_CB(smmu_domain->smmu, cfg->cbndx);
- bool use_tlbiall = smmu->options & ARM_SMMU_OPT_NO_ASID_RETENTION;
- ktime_t cur = ktime_get();
-
- trace_tlbi_start(dev, 0);
-
- if (!use_tlbiall)
- writel_relaxed(cfg->asid, base + ARM_SMMU_CB_S1_TLBIASID);
- else
- writel_relaxed(0, base + ARM_SMMU_CB_S1_TLBIALL);
-
- arm_smmu_tlb_sync_context(cookie);
- trace_tlbi_end(dev, ktime_us_delta(ktime_get(), cur));
+ return;
}
static void arm_smmu_tlb_inv_context_s2(void *cookie)
@@ -1483,6 +1490,7 @@ static phys_addr_t arm_smmu_verify_fault(struct iommu_domain *domain,
phys = arm_smmu_iova_to_phys_hard(domain, iova);
smmu_domain->pgtbl_cfg.tlb->tlb_flush_all(smmu_domain);
+ smmu_domain->pgtbl_cfg.tlb->tlb_sync(smmu_domain);
phys_post_tlbiall = arm_smmu_iova_to_phys_hard(domain, iova);
if (phys != phys_post_tlbiall) {
@@ -2539,6 +2547,7 @@ static void arm_smmu_domain_remove_master(struct arm_smmu_domain *smmu_domain,
/* Ensure there are no stale mappings for this context bank */
tlb->tlb_flush_all(smmu_domain);
+ tlb->tlb_sync(smmu_domain);
}
static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain,
@@ -3025,17 +3034,12 @@ static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
if (arm_smmu_is_slave_side_secure(smmu_domain))
return msm_secure_smmu_unmap(domain, iova, size);
- ret = arm_smmu_domain_power_on(domain, smmu_domain->smmu);
- if (ret)
- return ret;
-
arm_smmu_secure_domain_lock(smmu_domain);
spin_lock_irqsave(&smmu_domain->cb_lock, flags);
ret = ops->unmap(ops, iova, size);
spin_unlock_irqrestore(&smmu_domain->cb_lock, flags);
- arm_smmu_domain_power_off(domain, smmu_domain->smmu);
/*
* While splitting up block mappings, we might allocate page table
* memory during unmap, so the vmids needs to be assigned to the
@@ -3194,6 +3198,14 @@ static phys_addr_t arm_smmu_iova_to_phys(struct iommu_domain *domain,
return ret;
}
+static void arm_smmu_iotlb_sync(struct iommu_domain *domain)
+{
+ struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+
+ if (smmu_domain->tlb_ops)
+ smmu_domain->tlb_ops->tlb_sync(smmu_domain);
+}
+
/*
* This function can sleep, and cannot be called from atomic context. Will
* power on register block if required. This restriction does not apply to the
@@ -3960,6 +3972,8 @@ static struct iommu_ops arm_smmu_ops = {
.map = arm_smmu_map,
.unmap = arm_smmu_unmap,
.map_sg = arm_smmu_map_sg,
+ .flush_iotlb_all = arm_smmu_iotlb_sync,
+ .iotlb_sync = arm_smmu_iotlb_sync,
.iova_to_phys = arm_smmu_iova_to_phys,
.iova_to_phys_hard = arm_smmu_iova_to_phys_hard,
.add_device = arm_smmu_add_device,
diff --git a/drivers/iommu/dma-mapping-fast.c b/drivers/iommu/dma-mapping-fast.c
index 899d7c3e..ec88a51 100644
--- a/drivers/iommu/dma-mapping-fast.c
+++ b/drivers/iommu/dma-mapping-fast.c
@@ -153,6 +153,7 @@ static dma_addr_t __fast_smmu_alloc_iova(struct dma_fast_smmu_mapping *mapping,
bool skip_sync = (attrs & DMA_ATTR_SKIP_CPU_SYNC);
iommu_tlbiall(mapping->domain);
+ iommu_tlb_sync(mapping->domain);
mapping->have_stale_tlbs = false;
av8l_fast_clear_stale_ptes(mapping->pgtbl_ops, skip_sync);
}
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index c143901..b9af241 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -3721,7 +3721,7 @@ static void intel_unmap(struct device *dev, dma_addr_t dev_addr, size_t size)
freelist = domain_unmap(domain, start_pfn, last_pfn);
- if (intel_iommu_strict) {
+ if (intel_iommu_strict || !has_iova_flush_queue(&domain->iovad)) {
iommu_flush_iotlb_psi(iommu, domain, start_pfn,
nrpages, !freelist, 0);
/* free iova */
diff --git a/drivers/iommu/io-pgtable.c b/drivers/iommu/io-pgtable.c
index 541abb2..688e037 100644
--- a/drivers/iommu/io-pgtable.c
+++ b/drivers/iommu/io-pgtable.c
@@ -86,6 +86,7 @@ void free_io_pgtable_ops(struct io_pgtable_ops *ops)
iop = container_of(ops, struct io_pgtable, ops);
io_pgtable_tlb_flush_all(iop);
+ io_pgtable_tlb_sync(iop);
io_pgtable_init_table[iop->fmt]->free(iop);
}
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 462e496..ab8047ce 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -214,18 +214,21 @@ static int iommu_insert_resv_region(struct iommu_resv_region *new,
pos = pos->next;
} else if ((start >= a) && (end <= b)) {
if (new->type == type)
- goto done;
+ return 0;
else
pos = pos->next;
} else {
if (new->type == type) {
phys_addr_t new_start = min(a, start);
phys_addr_t new_end = max(b, end);
+ int ret;
list_del(&entry->list);
entry->start = new_start;
entry->length = new_end - new_start + 1;
- iommu_insert_resv_region(entry, regions);
+ ret = iommu_insert_resv_region(entry, regions);
+ kfree(entry);
+ return ret;
} else {
pos = pos->next;
}
@@ -238,7 +241,6 @@ static int iommu_insert_resv_region(struct iommu_resv_region *new,
return -ENOMEM;
list_add_tail(®ion->list, pos);
-done:
return 0;
}
diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c
index b7b3339..14651aa 100644
--- a/drivers/iommu/iova.c
+++ b/drivers/iommu/iova.c
@@ -65,9 +65,14 @@ init_iova_domain(struct iova_domain *iovad, unsigned long granule,
}
EXPORT_SYMBOL_GPL(init_iova_domain);
+bool has_iova_flush_queue(struct iova_domain *iovad)
+{
+ return !!iovad->fq;
+}
+
static void free_iova_flush_queue(struct iova_domain *iovad)
{
- if (!iovad->fq)
+ if (!has_iova_flush_queue(iovad))
return;
if (timer_pending(&iovad->fq_timer))
@@ -85,13 +90,14 @@ static void free_iova_flush_queue(struct iova_domain *iovad)
int init_iova_flush_queue(struct iova_domain *iovad,
iova_flush_cb flush_cb, iova_entry_dtor entry_dtor)
{
+ struct iova_fq __percpu *queue;
int cpu;
atomic64_set(&iovad->fq_flush_start_cnt, 0);
atomic64_set(&iovad->fq_flush_finish_cnt, 0);
- iovad->fq = alloc_percpu(struct iova_fq);
- if (!iovad->fq)
+ queue = alloc_percpu(struct iova_fq);
+ if (!queue)
return -ENOMEM;
iovad->flush_cb = flush_cb;
@@ -100,13 +106,17 @@ int init_iova_flush_queue(struct iova_domain *iovad,
for_each_possible_cpu(cpu) {
struct iova_fq *fq;
- fq = per_cpu_ptr(iovad->fq, cpu);
+ fq = per_cpu_ptr(queue, cpu);
fq->head = 0;
fq->tail = 0;
spin_lock_init(&fq->lock);
}
+ smp_wmb();
+
+ iovad->fq = queue;
+
timer_setup(&iovad->fq_timer, fq_flush_timeout, 0);
atomic_set(&iovad->fq_timer_on, 0);
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 65ab2c8..ee30e89 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -740,32 +740,43 @@ static void its_flush_cmd(struct its_node *its, struct its_cmd_block *cmd)
}
static int its_wait_for_range_completion(struct its_node *its,
- struct its_cmd_block *from,
+ u64 prev_idx,
struct its_cmd_block *to)
{
- u64 rd_idx, from_idx, to_idx;
+ u64 rd_idx, to_idx, linear_idx;
u32 count = 1000000; /* 1s! */
- from_idx = its_cmd_ptr_to_offset(its, from);
+ /* Linearize to_idx if the command set has wrapped around */
to_idx = its_cmd_ptr_to_offset(its, to);
+ if (to_idx < prev_idx)
+ to_idx += ITS_CMD_QUEUE_SZ;
+
+ linear_idx = prev_idx;
while (1) {
+ s64 delta;
+
rd_idx = readl_relaxed(its->base + GITS_CREADR);
- /* Direct case */
- if (from_idx < to_idx && rd_idx >= to_idx)
- break;
+ /*
+ * Compute the read pointer progress, taking the
+ * potential wrap-around into account.
+ */
+ delta = rd_idx - prev_idx;
+ if (rd_idx < prev_idx)
+ delta += ITS_CMD_QUEUE_SZ;
- /* Wrapped case */
- if (from_idx >= to_idx && rd_idx >= to_idx && rd_idx < from_idx)
+ linear_idx += delta;
+ if (linear_idx >= to_idx)
break;
count--;
if (!count) {
- pr_err_ratelimited("ITS queue timeout (%llu %llu %llu)\n",
- from_idx, to_idx, rd_idx);
+ pr_err_ratelimited("ITS queue timeout (%llu %llu)\n",
+ to_idx, linear_idx);
return -1;
}
+ prev_idx = rd_idx;
cpu_relax();
udelay(1);
}
@@ -782,6 +793,7 @@ void name(struct its_node *its, \
struct its_cmd_block *cmd, *sync_cmd, *next_cmd; \
synctype *sync_obj; \
unsigned long flags; \
+ u64 rd_idx; \
\
raw_spin_lock_irqsave(&its->lock, flags); \
\
@@ -803,10 +815,11 @@ void name(struct its_node *its, \
} \
\
post: \
+ rd_idx = readl_relaxed(its->base + GITS_CREADR); \
next_cmd = its_post_commands(its); \
raw_spin_unlock_irqrestore(&its->lock, flags); \
\
- if (its_wait_for_range_completion(its, cmd, next_cmd)) \
+ if (its_wait_for_range_completion(its, rd_idx, next_cmd)) \
pr_err_ratelimited("ITS cmd %ps failed\n", builder); \
}
diff --git a/drivers/irqchip/irq-meson-gpio.c b/drivers/irqchip/irq-meson-gpio.c
index 7b531fd..7599b10 100644
--- a/drivers/irqchip/irq-meson-gpio.c
+++ b/drivers/irqchip/irq-meson-gpio.c
@@ -73,6 +73,7 @@ static const struct of_device_id meson_irq_gpio_matches[] = {
{ .compatible = "amlogic,meson-gxbb-gpio-intc", .data = &gxbb_params },
{ .compatible = "amlogic,meson-gxl-gpio-intc", .data = &gxl_params },
{ .compatible = "amlogic,meson-axg-gpio-intc", .data = &axg_params },
+ { .compatible = "amlogic,meson-g12a-gpio-intc", .data = &axg_params },
{ }
};
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c
index 6d05946..060dc7f 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.c
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.c
@@ -1967,6 +1967,9 @@ hfcsusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
/* get endpoint base */
idx = ((ep_addr & 0x7f) - 1) * 2;
+ if (idx > 15)
+ return -EIO;
+
if (ep_addr & 0x80)
idx++;
attr = ep->desc.bmAttributes;
diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c
index 95be6e3..80710c6 100644
--- a/drivers/lightnvm/pblk-core.c
+++ b/drivers/lightnvm/pblk-core.c
@@ -288,14 +288,16 @@ void pblk_free_rqd(struct pblk *pblk, struct nvm_rq *rqd, int type)
void pblk_bio_free_pages(struct pblk *pblk, struct bio *bio, int off,
int nr_pages)
{
- struct bio_vec bv;
- int i;
+ struct bio_vec *bv;
+ struct page *page;
+ int i, e, nbv = 0;
- WARN_ON(off + nr_pages != bio->bi_vcnt);
-
- for (i = off; i < nr_pages + off; i++) {
- bv = bio->bi_io_vec[i];
- mempool_free(bv.bv_page, &pblk->page_bio_pool);
+ for (i = 0; i < bio->bi_vcnt; i++) {
+ bv = &bio->bi_io_vec[i];
+ page = bv->bv_page;
+ for (e = 0; e < bv->bv_len; e += PBLK_EXPOSED_PAGE_SIZE, nbv++)
+ if (nbv >= off)
+ mempool_free(page++, &pblk->page_bio_pool);
}
}
diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
index 5a5c566..db5aa29 100644
--- a/drivers/mailbox/mailbox.c
+++ b/drivers/mailbox/mailbox.c
@@ -409,11 +409,13 @@ struct mbox_chan *mbox_request_channel_byname(struct mbox_client *cl,
of_property_for_each_string(np, "mbox-names", prop, mbox_name) {
if (!strncmp(name, mbox_name, strlen(name)))
- break;
+ return mbox_request_channel(cl, index);
index++;
}
- return mbox_request_channel(cl, index);
+ dev_err(cl->dev, "%s() could not locate channel named \"%s\"\n",
+ __func__, name);
+ return ERR_PTR(-EINVAL);
}
EXPORT_SYMBOL_GPL(mbox_request_channel_byname);
diff --git a/drivers/md/bcache/alloc.c b/drivers/md/bcache/alloc.c
index de85b3a..9c3beb1 100644
--- a/drivers/md/bcache/alloc.c
+++ b/drivers/md/bcache/alloc.c
@@ -393,6 +393,11 @@ long bch_bucket_alloc(struct cache *ca, unsigned int reserve, bool wait)
struct bucket *b;
long r;
+
+ /* No allocation if CACHE_SET_IO_DISABLE bit is set */
+ if (unlikely(test_bit(CACHE_SET_IO_DISABLE, &ca->set->flags)))
+ return -1;
+
/* fastpath */
if (fifo_pop(&ca->free[RESERVE_NONE], r) ||
fifo_pop(&ca->free[reserve], r))
@@ -484,6 +489,10 @@ int __bch_bucket_alloc_set(struct cache_set *c, unsigned int reserve,
{
int i;
+ /* No allocation if CACHE_SET_IO_DISABLE bit is set */
+ if (unlikely(test_bit(CACHE_SET_IO_DISABLE, &c->flags)))
+ return -1;
+
lockdep_assert_held(&c->bucket_lock);
BUG_ON(!n || n > c->caches_loaded || n > 8);
diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h
index 954dad2..83f0b91 100644
--- a/drivers/md/bcache/bcache.h
+++ b/drivers/md/bcache/bcache.h
@@ -708,8 +708,6 @@ struct cache_set {
#define BUCKET_HASH_BITS 12
struct hlist_head bucket_hash[1 << BUCKET_HASH_BITS];
-
- DECLARE_HEAP(struct btree *, flush_btree);
};
struct bbio {
diff --git a/drivers/md/bcache/io.c b/drivers/md/bcache/io.c
index c250979..4d93f07 100644
--- a/drivers/md/bcache/io.c
+++ b/drivers/md/bcache/io.c
@@ -58,6 +58,18 @@ void bch_count_backing_io_errors(struct cached_dev *dc, struct bio *bio)
WARN_ONCE(!dc, "NULL pointer of struct cached_dev");
+ /*
+ * Read-ahead requests on a degrading and recovering md raid
+ * (e.g. raid6) device might be failured immediately by md
+ * raid code, which is not a real hardware media failure. So
+ * we shouldn't count failed REQ_RAHEAD bio to dc->io_errors.
+ */
+ if (bio->bi_opf & REQ_RAHEAD) {
+ pr_warn_ratelimited("%s: Read-ahead I/O failed on backing device, ignore",
+ dc->backing_dev_name);
+ return;
+ }
+
errors = atomic_add_return(1, &dc->io_errors);
if (errors < dc->error_limit)
pr_err("%s: IO error on backing device, unrecoverable",
diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c
index f880e5e..ec1e35a 100644
--- a/drivers/md/bcache/journal.c
+++ b/drivers/md/bcache/journal.c
@@ -390,12 +390,6 @@ int bch_journal_replay(struct cache_set *s, struct list_head *list)
}
/* Journalling */
-#define journal_max_cmp(l, r) \
- (fifo_idx(&c->journal.pin, btree_current_write(l)->journal) < \
- fifo_idx(&(c)->journal.pin, btree_current_write(r)->journal))
-#define journal_min_cmp(l, r) \
- (fifo_idx(&c->journal.pin, btree_current_write(l)->journal) > \
- fifo_idx(&(c)->journal.pin, btree_current_write(r)->journal))
static void btree_flush_write(struct cache_set *c)
{
@@ -403,35 +397,25 @@ static void btree_flush_write(struct cache_set *c)
* Try to find the btree node with that references the oldest journal
* entry, best is our current candidate and is locked if non NULL:
*/
- struct btree *b;
- int i;
+ struct btree *b, *best;
+ unsigned int i;
atomic_long_inc(&c->flush_write);
-
retry:
- spin_lock(&c->journal.lock);
- if (heap_empty(&c->flush_btree)) {
- for_each_cached_btree(b, c, i)
- if (btree_current_write(b)->journal) {
- if (!heap_full(&c->flush_btree))
- heap_add(&c->flush_btree, b,
- journal_max_cmp);
- else if (journal_max_cmp(b,
- heap_peek(&c->flush_btree))) {
- c->flush_btree.data[0] = b;
- heap_sift(&c->flush_btree, 0,
- journal_max_cmp);
- }
+ best = NULL;
+
+ for_each_cached_btree(b, c, i)
+ if (btree_current_write(b)->journal) {
+ if (!best)
+ best = b;
+ else if (journal_pin_cmp(c,
+ btree_current_write(best)->journal,
+ btree_current_write(b)->journal)) {
+ best = b;
}
+ }
- for (i = c->flush_btree.used / 2 - 1; i >= 0; --i)
- heap_sift(&c->flush_btree, i, journal_min_cmp);
- }
-
- b = NULL;
- heap_pop(&c->flush_btree, b, journal_min_cmp);
- spin_unlock(&c->journal.lock);
-
+ b = best;
if (b) {
mutex_lock(&b->write_lock);
if (!btree_current_write(b)->journal) {
@@ -810,6 +794,10 @@ atomic_t *bch_journal(struct cache_set *c,
struct journal_write *w;
atomic_t *ret;
+ /* No journaling if CACHE_SET_IO_DISABLE set already */
+ if (unlikely(test_bit(CACHE_SET_IO_DISABLE, &c->flags)))
+ return NULL;
+
if (!CACHE_SYNC(&c->sb))
return NULL;
@@ -854,7 +842,6 @@ void bch_journal_free(struct cache_set *c)
free_pages((unsigned long) c->journal.w[1].data, JSET_BITS);
free_pages((unsigned long) c->journal.w[0].data, JSET_BITS);
free_fifo(&c->journal.pin);
- free_heap(&c->flush_btree);
}
int bch_journal_alloc(struct cache_set *c)
@@ -869,8 +856,7 @@ int bch_journal_alloc(struct cache_set *c)
j->w[0].c = c;
j->w[1].c = c;
- if (!(init_heap(&c->flush_btree, 128, GFP_KERNEL)) ||
- !(init_fifo(&j->pin, JOURNAL_PIN, GFP_KERNEL)) ||
+ if (!(init_fifo(&j->pin, JOURNAL_PIN, GFP_KERNEL)) ||
!(j->w[0].data = (void *) __get_free_pages(GFP_KERNEL, JSET_BITS)) ||
!(j->w[1].data = (void *) __get_free_pages(GFP_KERNEL, JSET_BITS)))
return -ENOMEM;
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index 2409507..e6c7a84 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -1180,18 +1180,16 @@ static void cached_dev_free(struct closure *cl)
{
struct cached_dev *dc = container_of(cl, struct cached_dev, disk.cl);
- mutex_lock(&bch_register_lock);
-
if (test_and_clear_bit(BCACHE_DEV_WB_RUNNING, &dc->disk.flags))
cancel_writeback_rate_update_dwork(dc);
if (!IS_ERR_OR_NULL(dc->writeback_thread))
kthread_stop(dc->writeback_thread);
- if (dc->writeback_write_wq)
- destroy_workqueue(dc->writeback_write_wq);
if (!IS_ERR_OR_NULL(dc->status_update_thread))
kthread_stop(dc->status_update_thread);
+ mutex_lock(&bch_register_lock);
+
if (atomic_read(&dc->running))
bd_unlink_disk_holder(dc->bdev, dc->disk.disk);
bcache_device_free(&dc->disk);
@@ -1425,8 +1423,6 @@ int bch_flash_dev_create(struct cache_set *c, uint64_t size)
bool bch_cached_dev_error(struct cached_dev *dc)
{
- struct cache_set *c;
-
if (!dc || test_bit(BCACHE_DEV_CLOSING, &dc->disk.flags))
return false;
@@ -1437,21 +1433,6 @@ bool bch_cached_dev_error(struct cached_dev *dc)
pr_err("stop %s: too many IO errors on backing device %s\n",
dc->disk.disk->disk_name, dc->backing_dev_name);
- /*
- * If the cached device is still attached to a cache set,
- * even dc->io_disable is true and no more I/O requests
- * accepted, cache device internal I/O (writeback scan or
- * garbage collection) may still prevent bcache device from
- * being stopped. So here CACHE_SET_IO_DISABLE should be
- * set to c->flags too, to make the internal I/O to cache
- * device rejected and stopped immediately.
- * If c is NULL, that means the bcache device is not attached
- * to any cache set, then no CACHE_SET_IO_DISABLE bit to set.
- */
- c = dc->disk.c;
- if (c && test_and_set_bit(CACHE_SET_IO_DISABLE, &c->flags))
- pr_info("CACHE_SET_IO_DISABLE already set");
-
bcache_device_stop(&dc->disk);
return true;
}
@@ -1552,7 +1533,7 @@ static void cache_set_flush(struct closure *cl)
kobject_put(&c->internal);
kobject_del(&c->kobj);
- if (c->gc_thread)
+ if (!IS_ERR_OR_NULL(c->gc_thread))
kthread_stop(c->gc_thread);
if (!IS_ERR_OR_NULL(c->root))
diff --git a/drivers/md/bcache/sysfs.c b/drivers/md/bcache/sysfs.c
index 541454b..5bb81e5 100644
--- a/drivers/md/bcache/sysfs.c
+++ b/drivers/md/bcache/sysfs.c
@@ -175,7 +175,7 @@ SHOW(__bch_cached_dev)
var_print(writeback_percent);
sysfs_hprint(writeback_rate,
wb ? atomic_long_read(&dc->writeback_rate.rate) << 9 : 0);
- sysfs_hprint(io_errors, atomic_read(&dc->io_errors));
+ sysfs_printf(io_errors, "%i", atomic_read(&dc->io_errors));
sysfs_printf(io_error_limit, "%i", dc->error_limit);
sysfs_printf(io_disable, "%i", dc->io_disable);
var_print(writeback_rate_update_seconds);
@@ -426,7 +426,7 @@ static struct attribute *bch_cached_dev_files[] = {
&sysfs_writeback_rate_p_term_inverse,
&sysfs_writeback_rate_minimum,
&sysfs_writeback_rate_debug,
- &sysfs_errors,
+ &sysfs_io_errors,
&sysfs_io_error_limit,
&sysfs_io_disable,
&sysfs_dirty_data,
diff --git a/drivers/md/bcache/util.h b/drivers/md/bcache/util.h
index 00aab6a..b1f5b7a 100644
--- a/drivers/md/bcache/util.h
+++ b/drivers/md/bcache/util.h
@@ -113,8 +113,6 @@ do { \
#define heap_full(h) ((h)->used == (h)->size)
-#define heap_empty(h) ((h)->used == 0)
-
#define DECLARE_FIFO(type, name) \
struct { \
size_t front, back, size, mask; \
diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c
index 08c3a9f..ba5395f 100644
--- a/drivers/md/bcache/writeback.c
+++ b/drivers/md/bcache/writeback.c
@@ -708,6 +708,10 @@ static int bch_writeback_thread(void *arg)
}
}
+ if (dc->writeback_write_wq) {
+ flush_workqueue(dc->writeback_write_wq);
+ destroy_workqueue(dc->writeback_write_wq);
+ }
cached_dev_put(dc);
wait_for_kthread_stop();
@@ -803,6 +807,7 @@ int bch_cached_dev_writeback_start(struct cached_dev *dc)
"bcache_writeback");
if (IS_ERR(dc->writeback_thread)) {
cached_dev_put(dc);
+ destroy_workqueue(dc->writeback_write_wq);
return PTR_ERR(dc->writeback_thread);
}
diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c
index dc385b7..b1d0ae2 100644
--- a/drivers/md/dm-bufio.c
+++ b/drivers/md/dm-bufio.c
@@ -1602,9 +1602,7 @@ dm_bufio_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
unsigned long freed;
c = container_of(shrink, struct dm_bufio_client, shrinker);
- if (sc->gfp_mask & __GFP_FS)
- dm_bufio_lock(c);
- else if (!dm_bufio_trylock(c))
+ if (!dm_bufio_trylock(c))
return SHRINK_STOP;
freed = __scan(c, sc->nr_to_scan, sc->gfp_mask);
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 680535f..59d17c4 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -563,7 +563,7 @@ static char **realloc_argv(unsigned *size, char **old_argv)
gfp = GFP_NOIO;
}
argv = kmalloc_array(new_size, sizeof(*argv), gfp);
- if (argv) {
+ if (argv && old_argv) {
memcpy(argv, old_argv, *size * sizeof(*argv));
*size = new_size;
}
diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c
index 7967c01e..b1124ac 100644
--- a/drivers/md/dm-verity-target.c
+++ b/drivers/md/dm-verity-target.c
@@ -236,8 +236,8 @@ static int verity_handle_err(struct dm_verity *v, enum verity_block_type type,
BUG();
}
- DMERR("%s: %s block %llu is corrupted", v->data_dev->name, type_str,
- block);
+ DMERR_LIMIT("%s: %s block %llu is corrupted", v->data_dev->name,
+ type_str, block);
if (v->corrupted_errs == DM_VERITY_MAX_CORRUPTED_ERRS)
DMERR("%s: reached maximum errors", v->data_dev->name);
diff --git a/drivers/md/dm-zoned-metadata.c b/drivers/md/dm-zoned-metadata.c
index d8334cd..4cdde7a 100644
--- a/drivers/md/dm-zoned-metadata.c
+++ b/drivers/md/dm-zoned-metadata.c
@@ -1594,30 +1594,6 @@ struct dm_zone *dmz_get_zone_for_reclaim(struct dmz_metadata *zmd)
}
/*
- * Activate a zone (increment its reference count).
- */
-void dmz_activate_zone(struct dm_zone *zone)
-{
- set_bit(DMZ_ACTIVE, &zone->flags);
- atomic_inc(&zone->refcount);
-}
-
-/*
- * Deactivate a zone. This decrement the zone reference counter
- * and clears the active state of the zone once the count reaches 0,
- * indicating that all BIOs to the zone have completed. Returns
- * true if the zone was deactivated.
- */
-void dmz_deactivate_zone(struct dm_zone *zone)
-{
- if (atomic_dec_and_test(&zone->refcount)) {
- WARN_ON(!test_bit(DMZ_ACTIVE, &zone->flags));
- clear_bit_unlock(DMZ_ACTIVE, &zone->flags);
- smp_mb__after_atomic();
- }
-}
-
-/*
* Get the zone mapping a chunk, if the chunk is mapped already.
* If no mapping exist and the operation is WRITE, a zone is
* allocated and used to map the chunk.
diff --git a/drivers/md/dm-zoned.h b/drivers/md/dm-zoned.h
index 12419f0..ed8de49 100644
--- a/drivers/md/dm-zoned.h
+++ b/drivers/md/dm-zoned.h
@@ -115,7 +115,6 @@ enum {
DMZ_BUF,
/* Zone internal state */
- DMZ_ACTIVE,
DMZ_RECLAIM,
DMZ_SEQ_WRITE_ERR,
};
@@ -128,7 +127,6 @@ enum {
#define dmz_is_empty(z) ((z)->wp_block == 0)
#define dmz_is_offline(z) test_bit(DMZ_OFFLINE, &(z)->flags)
#define dmz_is_readonly(z) test_bit(DMZ_READ_ONLY, &(z)->flags)
-#define dmz_is_active(z) test_bit(DMZ_ACTIVE, &(z)->flags)
#define dmz_in_reclaim(z) test_bit(DMZ_RECLAIM, &(z)->flags)
#define dmz_seq_write_err(z) test_bit(DMZ_SEQ_WRITE_ERR, &(z)->flags)
@@ -188,8 +186,30 @@ void dmz_unmap_zone(struct dmz_metadata *zmd, struct dm_zone *zone);
unsigned int dmz_nr_rnd_zones(struct dmz_metadata *zmd);
unsigned int dmz_nr_unmap_rnd_zones(struct dmz_metadata *zmd);
-void dmz_activate_zone(struct dm_zone *zone);
-void dmz_deactivate_zone(struct dm_zone *zone);
+/*
+ * Activate a zone (increment its reference count).
+ */
+static inline void dmz_activate_zone(struct dm_zone *zone)
+{
+ atomic_inc(&zone->refcount);
+}
+
+/*
+ * Deactivate a zone. This decrement the zone reference counter
+ * indicating that all BIOs to the zone have completed when the count is 0.
+ */
+static inline void dmz_deactivate_zone(struct dm_zone *zone)
+{
+ atomic_dec(&zone->refcount);
+}
+
+/*
+ * Test if a zone is active, that is, has a refcount > 0.
+ */
+static inline bool dmz_is_active(struct dm_zone *zone)
+{
+ return atomic_read(&zone->refcount);
+}
int dmz_lock_zone_reclaim(struct dm_zone *zone);
void dmz_unlock_zone_reclaim(struct dm_zone *zone);
diff --git a/drivers/md/md.c b/drivers/md/md.c
index b924f62..fb5d702 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -7625,9 +7625,9 @@ static void status_unused(struct seq_file *seq)
static int status_resync(struct seq_file *seq, struct mddev *mddev)
{
sector_t max_sectors, resync, res;
- unsigned long dt, db;
- sector_t rt;
- int scale;
+ unsigned long dt, db = 0;
+ sector_t rt, curr_mark_cnt, resync_mark_cnt;
+ int scale, recovery_active;
unsigned int per_milli;
if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ||
@@ -7716,22 +7716,30 @@ static int status_resync(struct seq_file *seq, struct mddev *mddev)
* db: blocks written from mark until now
* rt: remaining time
*
- * rt is a sector_t, so could be 32bit or 64bit.
- * So we divide before multiply in case it is 32bit and close
- * to the limit.
- * We scale the divisor (db) by 32 to avoid losing precision
- * near the end of resync when the number of remaining sectors
- * is close to 'db'.
- * We then divide rt by 32 after multiplying by db to compensate.
- * The '+1' avoids division by zero if db is very small.
+ * rt is a sector_t, which is always 64bit now. We are keeping
+ * the original algorithm, but it is not really necessary.
+ *
+ * Original algorithm:
+ * So we divide before multiply in case it is 32bit and close
+ * to the limit.
+ * We scale the divisor (db) by 32 to avoid losing precision
+ * near the end of resync when the number of remaining sectors
+ * is close to 'db'.
+ * We then divide rt by 32 after multiplying by db to compensate.
+ * The '+1' avoids division by zero if db is very small.
*/
dt = ((jiffies - mddev->resync_mark) / HZ);
if (!dt) dt++;
- db = (mddev->curr_mark_cnt - atomic_read(&mddev->recovery_active))
- - mddev->resync_mark_cnt;
+
+ curr_mark_cnt = mddev->curr_mark_cnt;
+ recovery_active = atomic_read(&mddev->recovery_active);
+ resync_mark_cnt = mddev->resync_mark_cnt;
+
+ if (curr_mark_cnt >= (recovery_active + resync_mark_cnt))
+ db = curr_mark_cnt - (recovery_active + resync_mark_cnt);
rt = max_sectors - resync; /* number of remaining sectors */
- sector_div(rt, db/32+1);
+ rt = div64_u64(rt, db/32+1);
rt *= dt;
rt >>= 5;
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index f237d6f..a147619 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -7670,7 +7670,7 @@ static int raid5_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
static int raid5_add_disk(struct mddev *mddev, struct md_rdev *rdev)
{
struct r5conf *conf = mddev->private;
- int err = -EEXIST;
+ int ret, err = -EEXIST;
int disk;
struct disk_info *p;
int first = 0;
@@ -7685,7 +7685,14 @@ static int raid5_add_disk(struct mddev *mddev, struct md_rdev *rdev)
* The array is in readonly mode if journal is missing, so no
* write requests running. We should be safe
*/
- log_init(conf, rdev, false);
+ ret = log_init(conf, rdev, false);
+ if (ret)
+ return ret;
+
+ ret = r5l_start(conf->log);
+ if (ret)
+ return ret;
+
return 0;
}
if (mddev->recovery_disabled == conf->recovery_disabled)
diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
index 9226dca..93d250d 100644
--- a/drivers/media/common/videobuf2/videobuf2-core.c
+++ b/drivers/media/common/videobuf2/videobuf2-core.c
@@ -207,6 +207,10 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
for (plane = 0; plane < vb->num_planes; ++plane) {
unsigned long size = PAGE_ALIGN(vb->planes[plane].length);
+ /* Did it wrap around? */
+ if (size < vb->planes[plane].length)
+ goto free;
+
mem_priv = call_ptr_memop(vb, alloc,
q->alloc_devs[plane] ? : q->dev,
q->dma_attrs, size, q->dma_dir, q->gfp_flags);
diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c
index 015e737..e9bfea9 100644
--- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c
+++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c
@@ -59,7 +59,7 @@ static int vb2_dma_sg_alloc_compacted(struct vb2_dma_sg_buf *buf,
gfp_t gfp_flags)
{
unsigned int last_page = 0;
- int size = buf->size;
+ unsigned long size = buf->size;
while (size > 0) {
struct page *pages;
diff --git a/drivers/media/dvb-frontends/stv0297.c b/drivers/media/dvb-frontends/stv0297.c
index 9a9915f..3ef31a3 100644
--- a/drivers/media/dvb-frontends/stv0297.c
+++ b/drivers/media/dvb-frontends/stv0297.c
@@ -694,7 +694,7 @@ static const struct dvb_frontend_ops stv0297_ops = {
.delsys = { SYS_DVBC_ANNEX_A },
.info = {
.name = "ST STV0297 DVB-C",
- .frequency_min_hz = 470 * MHz,
+ .frequency_min_hz = 47 * MHz,
.frequency_max_hz = 862 * MHz,
.frequency_stepsize_hz = 62500,
.symbol_rate_min = 870000,
diff --git a/drivers/media/dvb-frontends/tua6100.c b/drivers/media/dvb-frontends/tua6100.c
index b233b7b..e6aaf49 100644
--- a/drivers/media/dvb-frontends/tua6100.c
+++ b/drivers/media/dvb-frontends/tua6100.c
@@ -75,8 +75,8 @@ static int tua6100_set_params(struct dvb_frontend *fe)
struct i2c_msg msg1 = { .addr = priv->i2c_address, .flags = 0, .buf = reg1, .len = 4 };
struct i2c_msg msg2 = { .addr = priv->i2c_address, .flags = 0, .buf = reg2, .len = 3 };
-#define _R 4
-#define _P 32
+#define _R_VAL 4
+#define _P_VAL 32
#define _ri 4000000
// setup register 0
@@ -91,14 +91,14 @@ static int tua6100_set_params(struct dvb_frontend *fe)
else
reg1[1] = 0x0c;
- if (_P == 64)
+ if (_P_VAL == 64)
reg1[1] |= 0x40;
if (c->frequency >= 1525000)
reg1[1] |= 0x80;
// register 2
- reg2[1] = (_R >> 8) & 0x03;
- reg2[2] = _R;
+ reg2[1] = (_R_VAL >> 8) & 0x03;
+ reg2[2] = _R_VAL;
if (c->frequency < 1455000)
reg2[1] |= 0x1c;
else if (c->frequency < 1630000)
@@ -110,18 +110,18 @@ static int tua6100_set_params(struct dvb_frontend *fe)
* The N divisor ratio (note: c->frequency is in kHz, but we
* need it in Hz)
*/
- prediv = (c->frequency * _R) / (_ri / 1000);
- div = prediv / _P;
+ prediv = (c->frequency * _R_VAL) / (_ri / 1000);
+ div = prediv / _P_VAL;
reg1[1] |= (div >> 9) & 0x03;
reg1[2] = div >> 1;
reg1[3] = (div << 7);
- priv->frequency = ((div * _P) * (_ri / 1000)) / _R;
+ priv->frequency = ((div * _P_VAL) * (_ri / 1000)) / _R_VAL;
// Finally, calculate and store the value for A
- reg1[3] |= (prediv - (div*_P)) & 0x7f;
+ reg1[3] |= (prediv - (div*_P_VAL)) & 0x7f;
-#undef _R
-#undef _P
+#undef _R_VAL
+#undef _P_VAL
#undef _ri
if (fe->ops.i2c_gate_ctrl)
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index a94eb03..520b3c3 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -36,7 +36,7 @@
obj-$(CONFIG_VIDEO_ADV7604) += adv7604.o
obj-$(CONFIG_VIDEO_ADV7842) += adv7842.o
obj-$(CONFIG_VIDEO_AD9389B) += ad9389b.o
-obj-$(CONFIG_VIDEO_ADV7511) += adv7511.o
+obj-$(CONFIG_VIDEO_ADV7511) += adv7511-v4l2.o
obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o
obj-$(CONFIG_VIDEO_VS6624) += vs6624.o
obj-$(CONFIG_VIDEO_BT819) += bt819.o
diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511-v4l2.c
similarity index 99%
rename from drivers/media/i2c/adv7511.c
rename to drivers/media/i2c/adv7511-v4l2.c
index 88349b5..6869bb5 100644
--- a/drivers/media/i2c/adv7511.c
+++ b/drivers/media/i2c/adv7511-v4l2.c
@@ -5,6 +5,11 @@
* Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
*/
+/*
+ * This file is named adv7511-v4l2.c so it doesn't conflict with the Analog
+ * Device ADV7511 (config fragment CONFIG_DRM_I2C_ADV7511).
+ */
+
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c
index f5a1ee9..8a6a7a5 100644
--- a/drivers/media/i2c/ov7740.c
+++ b/drivers/media/i2c/ov7740.c
@@ -761,7 +761,11 @@ static int ov7740_try_fmt_internal(struct v4l2_subdev *sd,
fsize++;
}
-
+ if (i >= ARRAY_SIZE(ov7740_framesizes)) {
+ fsize = &ov7740_framesizes[0];
+ fmt->width = fsize->width;
+ fmt->height = fsize->height;
+ }
if (ret_frmsize != NULL)
*ret_frmsize = fsize;
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 3bae24b..ed518b1 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -487,6 +487,7 @@ static long media_device_enum_links32(struct media_device *mdev,
{
struct media_links_enum links;
compat_uptr_t pads_ptr, links_ptr;
+ int ret;
memset(&links, 0, sizeof(links));
@@ -498,7 +499,14 @@ static long media_device_enum_links32(struct media_device *mdev,
links.pads = compat_ptr(pads_ptr);
links.links = compat_ptr(links_ptr);
- return media_device_enum_links(mdev, &links);
+ ret = media_device_enum_links(mdev, &links);
+ if (ret)
+ return ret;
+
+ if (copy_to_user(ulinks->reserved, links.reserved,
+ sizeof(ulinks->reserved)))
+ return -EFAULT;
+ return 0;
}
#define MEDIA_IOC_ENUM_LINKS32 _IOWR('|', 0x02, struct media_links_enum32)
diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c
index d697e1a..5102519 100644
--- a/drivers/media/pci/saa7164/saa7164-core.c
+++ b/drivers/media/pci/saa7164/saa7164-core.c
@@ -1122,16 +1122,25 @@ static int saa7164_proc_show(struct seq_file *m, void *v)
return 0;
}
+static struct proc_dir_entry *saa7164_pe;
+
static int saa7164_proc_create(void)
{
- struct proc_dir_entry *pe;
-
- pe = proc_create_single("saa7164", S_IRUGO, NULL, saa7164_proc_show);
- if (!pe)
+ saa7164_pe = proc_create_single("saa7164", 0444, NULL, saa7164_proc_show);
+ if (!saa7164_pe)
return -ENOMEM;
return 0;
}
+
+static void saa7164_proc_destroy(void)
+{
+ if (saa7164_pe)
+ remove_proc_entry("saa7164", NULL);
+}
+#else
+static int saa7164_proc_create(void) { return 0; }
+static void saa7164_proc_destroy(void) {}
#endif
static int saa7164_thread_function(void *data)
@@ -1503,19 +1512,21 @@ static struct pci_driver saa7164_pci_driver = {
static int __init saa7164_init(void)
{
- printk(KERN_INFO "saa7164 driver loaded\n");
+ int ret = pci_register_driver(&saa7164_pci_driver);
-#ifdef CONFIG_PROC_FS
+ if (ret)
+ return ret;
+
saa7164_proc_create();
-#endif
- return pci_register_driver(&saa7164_pci_driver);
+
+ pr_info("saa7164 driver loaded\n");
+
+ return 0;
}
static void __exit saa7164_fini(void)
{
-#ifdef CONFIG_PROC_FS
- remove_proc_entry("saa7164", NULL);
-#endif
+ saa7164_proc_destroy();
pci_unregister_driver(&saa7164_pci_driver);
}
diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c
index a3cfefd..c3eaddc 100644
--- a/drivers/media/platform/coda/coda-bit.c
+++ b/drivers/media/platform/coda/coda-bit.c
@@ -1728,6 +1728,7 @@ static int __coda_start_decoding(struct coda_ctx *ctx)
v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n");
return ret;
}
+ ctx->sequence_offset = ~0U;
ctx->initialized = 1;
/* Update kfifo out pointer from coda bitstream read pointer */
@@ -2142,12 +2143,17 @@ static void coda_finish_decode(struct coda_ctx *ctx)
else if (ctx->display_idx < 0)
ctx->hold = true;
} else if (decoded_idx == -2) {
+ if (ctx->display_idx >= 0 &&
+ ctx->display_idx < ctx->num_internal_frames)
+ ctx->sequence_offset++;
/* no frame was decoded, we still return remaining buffers */
} else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) {
v4l2_err(&dev->v4l2_dev,
"decoded frame index out of range: %d\n", decoded_idx);
} else {
- val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1;
+ val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM);
+ if (ctx->sequence_offset == -1)
+ ctx->sequence_offset = val;
val -= ctx->sequence_offset;
spin_lock_irqsave(&ctx->buffer_meta_lock, flags);
if (!list_empty(&ctx->buffer_meta_list)) {
@@ -2303,7 +2309,6 @@ irqreturn_t coda_irq_handler(int irq, void *data)
if (ctx == NULL) {
v4l2_err(&dev->v4l2_dev,
"Instance released before the end of transaction\n");
- mutex_unlock(&dev->coda_mutex);
return IRQ_HANDLED;
}
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c
index 19d92ed..4b0220f 100644
--- a/drivers/media/platform/coda/coda-common.c
+++ b/drivers/media/platform/coda/coda-common.c
@@ -997,6 +997,8 @@ static int coda_encoder_cmd(struct file *file, void *fh,
/* Set the stream-end flag on this context */
ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
+ flush_work(&ctx->pic_run_work);
+
/* If there is no buffer in flight, wake up */
if (!ctx->streamon_out || ctx->qsequence == ctx->osequence) {
dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
diff --git a/drivers/media/platform/davinci/vpss.c b/drivers/media/platform/davinci/vpss.c
index 19cf685..89a86c1 100644
--- a/drivers/media/platform/davinci/vpss.c
+++ b/drivers/media/platform/davinci/vpss.c
@@ -518,6 +518,11 @@ static int __init vpss_init(void)
return -EBUSY;
oper_cfg.vpss_regs_base2 = ioremap(VPSS_CLK_CTRL, 4);
+ if (unlikely(!oper_cfg.vpss_regs_base2)) {
+ release_mem_region(VPSS_CLK_CTRL, 4);
+ return -ENOMEM;
+ }
+
writel(VPSS_CLK_CTRL_VENCCLKEN |
VPSS_CLK_CTRL_DACCLKEN, oper_cfg.vpss_regs_base2);
diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c
index dfdbd43..eeee15f 100644
--- a/drivers/media/platform/marvell-ccic/mcam-core.c
+++ b/drivers/media/platform/marvell-ccic/mcam-core.c
@@ -200,7 +200,6 @@ struct mcam_vb_buffer {
struct list_head queue;
struct mcam_dma_desc *dma_desc; /* Descriptor virtual address */
dma_addr_t dma_desc_pa; /* Descriptor physical address */
- int dma_desc_nent; /* Number of mapped descriptors */
};
static inline struct mcam_vb_buffer *vb_to_mvb(struct vb2_v4l2_buffer *vb)
@@ -608,9 +607,11 @@ static void mcam_dma_contig_done(struct mcam_camera *cam, int frame)
static void mcam_sg_next_buffer(struct mcam_camera *cam)
{
struct mcam_vb_buffer *buf;
+ struct sg_table *sg_table;
buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue);
list_del_init(&buf->queue);
+ sg_table = vb2_dma_sg_plane_desc(&buf->vb_buf.vb2_buf, 0);
/*
* Very Bad Not Good Things happen if you don't clear
* C1_DESC_ENA before making any descriptor changes.
@@ -618,7 +619,7 @@ static void mcam_sg_next_buffer(struct mcam_camera *cam)
mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_ENA);
mcam_reg_write(cam, REG_DMA_DESC_Y, buf->dma_desc_pa);
mcam_reg_write(cam, REG_DESC_LEN_Y,
- buf->dma_desc_nent*sizeof(struct mcam_dma_desc));
+ sg_table->nents * sizeof(struct mcam_dma_desc));
mcam_reg_write(cam, REG_DESC_LEN_U, 0);
mcam_reg_write(cam, REG_DESC_LEN_V, 0);
mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA);
diff --git a/drivers/media/platform/msm/cvp/cvp_core_hfi.h b/drivers/media/platform/msm/cvp/cvp_core_hfi.h
index 59b67b8..5481ea2 100644
--- a/drivers/media/platform/msm/cvp/cvp_core_hfi.h
+++ b/drivers/media/platform/msm/cvp/cvp_core_hfi.h
@@ -266,6 +266,7 @@ struct iris_hfi_device {
unsigned int skip_pc_count;
struct msm_cvp_capability *sys_init_capabilities;
struct iris_hfi_vpu_ops *vpu_ops;
+ struct delayed_work dsp_init_work;
};
void cvp_iris_hfi_delete_device(void *device);
diff --git a/drivers/media/platform/msm/cvp/cvp_hfi.c b/drivers/media/platform/msm/cvp/cvp_hfi.c
index dac2b90..24b6296 100644
--- a/drivers/media/platform/msm/cvp/cvp_hfi.c
+++ b/drivers/media/platform/msm/cvp/cvp_hfi.c
@@ -238,8 +238,6 @@ const struct msm_cvp_hfi_defs cvp_hfi_defs[] = {
};
-static struct cvp_hal_device_data hal_ctxt;
-
struct cvp_tzbsp_memprot {
u32 cp_start;
u32 cp_size;
@@ -268,6 +266,7 @@ const int cvp_max_packets = 32;
static void iris_hfi_pm_handler(struct work_struct *work);
static DECLARE_DELAYED_WORK(iris_hfi_pm_work, iris_hfi_pm_handler);
+static void dsp_init_work_handler(struct work_struct *work);
static inline int __resume(struct iris_hfi_device *device);
static inline int __suspend(struct iris_hfi_device *device);
static int __disable_regulators(struct iris_hfi_device *device);
@@ -508,7 +507,7 @@ static int __dsp_send_hfi_queue(struct iris_hfi_device *device)
(phys_addr_t *)device->dsp_iface_q_table.mem_data.dma_handle,
device->dsp_iface_q_table.mem_data.size);
if (rc) {
- dprintk(CVP_ERR, "%s: dsp init failed\n", __func__);
+ dprintk(CVP_ERR, "%s: dsp hfi queue init failed\n", __func__);
return rc;
}
@@ -1382,6 +1381,32 @@ static int iris_hfi_suspend(void *dev)
return rc;
}
+static void cvp_dump_csr(struct iris_hfi_device *dev)
+{
+ u32 reg;
+
+ if (!dev)
+ return;
+ if (!dev->power_enabled)
+ return;
+ reg = __read_register(dev, CVP_WRAPPER_CPU_STATUS);
+ dprintk(CVP_ERR, "CVP_WRAPPER_CPU_STATUS: %x\n", reg);
+ reg = __read_register(dev, CVP_CPU_CS_SCIACMDARG0);
+ dprintk(CVP_ERR, "CVP_CPU_CS_SCIACMDARG0: %x\n", reg);
+ reg = __read_register(dev, CVP_WRAPPER_CPU_CLOCK_CONFIG);
+ dprintk(CVP_ERR, "CVP_WRAPPER_CPU_CLOCK_CONFIG: %x\n", reg);
+ reg = __read_register(dev, CVP_WRAPPER_INTR_STATUS);
+ dprintk(CVP_ERR, "CVP_WRAPPER_INTR_STATUS: %x\n", reg);
+ reg = __read_register(dev, CVP_CPU_CS_H2ASOFTINT);
+ dprintk(CVP_ERR, "CVP_CPU_CS_H2ASOFTINT: %x\n", reg);
+ reg = __read_register(dev, CVP_CPU_CS_A2HSOFTINT);
+ dprintk(CVP_ERR, "CVP_CPU_CS_A2HSOFTINT: %x\n", reg);
+ reg = __read_register(dev, CVP_CC_MVS0C_GDSCR);
+ dprintk(CVP_ERR, "CVP_CC_MVS0C_GDSCR: %x\n", reg);
+ reg = __read_register(dev, CVP_CC_MVS1C_GDSCR);
+ dprintk(CVP_ERR, "CVP_CC_MVS1C_GDSCR: %x\n", reg);
+}
+
static int iris_hfi_flush_debug_queue(void *dev)
{
int rc = 0;
@@ -1392,6 +1417,7 @@ static int iris_hfi_flush_debug_queue(void *dev)
return -EINVAL;
}
+ cvp_dump_csr(device);
mutex_lock(&device->lock);
if (!device->power_enabled) {
@@ -2036,7 +2062,8 @@ static int __interface_queues_init(struct iris_hfi_device *dev)
}
vsfr = (struct cvp_hfi_sfr_struct *) dev->sfr.align_virtual_addr;
- vsfr->bufSize = ALIGNED_SFR_SIZE;
+ if (vsfr)
+ vsfr->bufSize = ALIGNED_SFR_SIZE;
rc = __interface_dsp_queues_init(dev);
if (rc) {
@@ -2131,6 +2158,43 @@ static int __sys_set_power_control(struct iris_hfi_device *device,
return 0;
}
+static void dsp_init_work_handler(struct work_struct *work)
+{
+ int rc = 0;
+ static int retry_count;
+ struct iris_hfi_device *device;
+
+ if (!work) {
+ dprintk(CVP_ERR, "%s: NULL device\n", __func__);
+ return;
+ }
+
+ device = container_of(work, struct iris_hfi_device, dsp_init_work.work);
+ if (!device) {
+ dprintk(CVP_ERR, "%s: NULL device\n", __func__);
+ return;
+ }
+
+ dprintk(CVP_PROF, "Entering %s\n", __func__);
+
+ mutex_lock(&device->lock);
+ rc = __dsp_send_hfi_queue(device);
+ mutex_unlock(&device->lock);
+
+ if (rc) {
+ if (retry_count > MAX_DSP_INIT_ATTEMPTS) {
+ dprintk(CVP_ERR, "%s: max trials exceeded\n", __func__);
+ return;
+ }
+ dprintk(CVP_PROF, "%s: Attempt to init DSP %d\n",
+ __func__, retry_count);
+
+ schedule_delayed_work(&device->dsp_init_work,
+ msecs_to_jiffies(CVP_MAX_WAIT_TIME));
+ ++retry_count;
+ }
+}
+
static int iris_hfi_core_init(void *device)
{
int rc = 0;
@@ -2208,7 +2272,6 @@ static int iris_hfi_core_init(void *device)
__enable_subcaches(device);
__set_subcaches(device);
- __dsp_send_hfi_queue(device);
__set_ubwc_config(device);
__sys_set_idle_indicator(device, true);
@@ -2221,9 +2284,15 @@ static int iris_hfi_core_init(void *device)
pm_qos_add_request(&dev->qos, PM_QOS_CPU_DMA_LATENCY,
dev->res->pm_qos_latency_us);
}
+
+ rc = __dsp_send_hfi_queue(device);
+ if (rc)
+ schedule_delayed_work(&dev->dsp_init_work,
+ msecs_to_jiffies(CVP_MAX_WAIT_TIME));
+
dprintk(CVP_DBG, "Core inited successfully\n");
mutex_unlock(&dev->lock);
- return rc;
+ return 0;
err_core_init:
__set_state(dev, IRIS_STATE_DEINIT);
__unload_fw(dev);
@@ -2653,49 +2722,45 @@ static int iris_hfi_session_send(void *sess,
return rc;
}
-static int __check_core_registered(struct cvp_hal_device_data core,
+static int __check_core_registered(struct iris_hfi_device *device,
phys_addr_t fw_addr, u8 *reg_addr, u32 reg_size,
phys_addr_t irq)
{
- struct iris_hfi_device *device;
struct cvp_hal_data *cvp_hal_data;
- struct list_head *curr, *next;
- if (!core.dev_count) {
+ if (!device) {
dprintk(CVP_INFO, "no device Registered\n");
return -EINVAL;
}
- list_for_each_safe(curr, next, &core.dev_head) {
- device = list_entry(curr,
- struct iris_hfi_device, list);
- cvp_hal_data = device->cvp_hal_data;
- if (device && cvp_hal_data->irq == irq &&
- (CONTAINS(cvp_hal_data->firmware_base,
- FIRMWARE_SIZE, fw_addr) ||
- CONTAINS(fw_addr, FIRMWARE_SIZE,
- cvp_hal_data->firmware_base) ||
- CONTAINS(cvp_hal_data->register_base,
- reg_size, reg_addr) ||
- CONTAINS(reg_addr, reg_size,
- cvp_hal_data->register_base) ||
- OVERLAPS(cvp_hal_data->register_base,
- reg_size, reg_addr, reg_size) ||
- OVERLAPS(reg_addr, reg_size,
- cvp_hal_data->register_base,
- reg_size) ||
- OVERLAPS(cvp_hal_data->firmware_base,
- FIRMWARE_SIZE, fw_addr,
- FIRMWARE_SIZE) ||
- OVERLAPS(fw_addr, FIRMWARE_SIZE,
- cvp_hal_data->firmware_base,
- FIRMWARE_SIZE))) {
- return 0;
- }
-
- dprintk(CVP_INFO, "Device not registered\n");
+ cvp_hal_data = device->cvp_hal_data;
+ if (!cvp_hal_data)
return -EINVAL;
+
+ if (cvp_hal_data->irq == irq &&
+ (CONTAINS(cvp_hal_data->firmware_base,
+ FIRMWARE_SIZE, fw_addr) ||
+ CONTAINS(fw_addr, FIRMWARE_SIZE,
+ cvp_hal_data->firmware_base) ||
+ CONTAINS(cvp_hal_data->register_base,
+ reg_size, reg_addr) ||
+ CONTAINS(reg_addr, reg_size,
+ cvp_hal_data->register_base) ||
+ OVERLAPS(cvp_hal_data->register_base,
+ reg_size, reg_addr, reg_size) ||
+ OVERLAPS(reg_addr, reg_size,
+ cvp_hal_data->register_base,
+ reg_size) ||
+ OVERLAPS(cvp_hal_data->firmware_base,
+ FIRMWARE_SIZE, fw_addr,
+ FIRMWARE_SIZE) ||
+ OVERLAPS(fw_addr, FIRMWARE_SIZE,
+ cvp_hal_data->firmware_base,
+ FIRMWARE_SIZE))) {
+ return 0;
}
+
+ dprintk(CVP_INFO, "Device not registered\n");
return -EINVAL;
}
@@ -2730,8 +2795,14 @@ static int __prepare_pc(struct iris_hfi_device *device)
static void iris_hfi_pm_handler(struct work_struct *work)
{
int rc = 0;
- struct iris_hfi_device *device = list_first_entry(
- &hal_ctxt.dev_head, struct iris_hfi_device, list);
+ struct msm_cvp_core *core;
+ struct iris_hfi_device *device;
+
+ core = list_first_entry(&cvp_driver->cores, struct msm_cvp_core, list);
+ if (core)
+ device = core->device->hfi_device_data;
+ else
+ return;
if (!device) {
dprintk(CVP_ERR, "%s: NULL device\n", __func__);
@@ -2790,7 +2861,7 @@ static int __power_collapse(struct iris_hfi_device *device, bool force)
u32 wfi_status = 0, idle_status = 0, pc_ready = 0;
u32 flags = 0;
int count = 0;
- const int max_tries = 10;
+ const int max_tries = 150;
if (!device) {
dprintk(CVP_ERR, "%s: invalid params\n", __func__);
@@ -3234,11 +3305,17 @@ static int __response_handler(struct iris_hfi_device *device)
static void iris_hfi_core_work_handler(struct work_struct *work)
{
- struct iris_hfi_device *device = list_first_entry(
- &hal_ctxt.dev_head, struct iris_hfi_device, list);
+ struct msm_cvp_core *core;
+ struct iris_hfi_device *device;
int num_responses = 0, i = 0;
u32 intr_status;
+ core = list_first_entry(&cvp_driver->cores, struct msm_cvp_core, list);
+ if (core)
+ device = core->device->hfi_device_data;
+ else
+ return;
+
mutex_lock(&device->lock);
@@ -3315,7 +3392,7 @@ static int __init_regs_and_interrupts(struct iris_hfi_device *device,
struct cvp_hal_data *hal = NULL;
int rc = 0;
- rc = __check_core_registered(hal_ctxt, res->firmware_base,
+ rc = __check_core_registered(device, res->firmware_base,
(u8 *)(uintptr_t)res->register_base,
res->register_size, res->irq);
if (!rc) {
@@ -4372,7 +4449,7 @@ static void power_off_iris2(struct iris_hfi_device *device)
CVP_AON_WRAPPER_MVP_NOC_LPI_STATUS);
reg_status = lpi_status & BIT(0);
dprintk(CVP_DBG,
- "Noc: lpi_status %d noc_status %d (count %d)\n",
+ "Noc: lpi_status %x noc_status %x (count %d)\n",
lpi_status, reg_status, count);
/* Wait for noc lpi status to be set */
@@ -4381,7 +4458,8 @@ static void power_off_iris2(struct iris_hfi_device *device)
}
if (count == max_count) {
dprintk(CVP_WARN,
- "NOC not in qaccept status %d\n", reg_status);
+ "NOC not in qaccept status %x %x\n",
+ reg_status, lpi_status);
}
/* HPG 6.1.2 Step 3, debug bridge to low power */
@@ -4403,7 +4481,7 @@ static void power_off_iris2(struct iris_hfi_device *device)
}
if (count == max_count) {
dprintk(CVP_WARN,
- "DBLP Set: status %d\n", reg_status);
+ "DBLP Set: status %x %x\n", reg_status, lpi_status);
}
/* HPG 6.1.2 Step 4, debug bridge to lpi release */
@@ -4422,7 +4500,7 @@ static void power_off_iris2(struct iris_hfi_device *device)
}
if (count == max_count) {
dprintk(CVP_WARN,
- "DBLP Release: lpi_status %d\n", lpi_status);
+ "DBLP Release: lpi_status %x\n", lpi_status);
}
/* HPG 6.1.2 Step 6 */
@@ -4594,7 +4672,7 @@ static void __unload_fw(struct iris_hfi_device *device)
device->resources.fw.cookie = NULL;
__deinit_resources(device);
- dprintk(CVP_DBG, "Firmware unloaded successfully\n");
+ dprintk(CVP_WARN, "Firmware unloaded\n");
}
static int iris_hfi_get_fw_info(void *dev, struct cvp_hal_fw_info *fw_info)
@@ -4817,14 +4895,10 @@ static struct iris_hfi_device *__add_device(u32 device_id,
goto err_cleanup;
}
- if (!hal_ctxt.dev_count)
- INIT_LIST_HEAD(&hal_ctxt.dev_head);
-
mutex_init(&hdevice->lock);
- INIT_LIST_HEAD(&hdevice->list);
INIT_LIST_HEAD(&hdevice->sess_head);
- list_add_tail(&hdevice->list, &hal_ctxt.dev_head);
- hal_ctxt.dev_count++;
+
+ INIT_DELAYED_WORK(&hdevice->dsp_init_work, dsp_init_work_handler);
return hdevice;
@@ -4854,30 +4928,29 @@ static struct iris_hfi_device *__get_device(u32 device_id,
void cvp_iris_hfi_delete_device(void *device)
{
- struct iris_hfi_device *close, *tmp, *dev;
+ struct msm_cvp_core *core;
+ struct iris_hfi_device *dev = NULL;
if (!device)
return;
- dev = (struct iris_hfi_device *) device;
+ core = list_first_entry(&cvp_driver->cores, struct msm_cvp_core, list);
+ if (core)
+ dev = core->device->hfi_device_data;
- list_for_each_entry_safe(close, tmp, &hal_ctxt.dev_head, list) {
- if (close->cvp_hal_data->irq == dev->cvp_hal_data->irq) {
- hal_ctxt.dev_count--;
- list_del(&close->list);
- mutex_destroy(&close->lock);
- destroy_workqueue(close->cvp_workq);
- destroy_workqueue(close->iris_pm_workq);
- free_irq(dev->cvp_hal_data->irq, close);
- iounmap(dev->cvp_hal_data->register_base);
- iounmap(dev->cvp_hal_data->gcc_reg_base);
- kfree(close->cvp_hal_data);
- kfree(close->response_pkt);
- kfree(close->raw_packet);
- kfree(close);
- break;
- }
- }
+ if (!dev)
+ return;
+
+ mutex_destroy(&dev->lock);
+ destroy_workqueue(dev->cvp_workq);
+ destroy_workqueue(dev->iris_pm_workq);
+ free_irq(dev->cvp_hal_data->irq, dev);
+ iounmap(dev->cvp_hal_data->register_base);
+ iounmap(dev->cvp_hal_data->gcc_reg_base);
+ kfree(dev->cvp_hal_data);
+ kfree(dev->response_pkt);
+ kfree(dev->raw_packet);
+ kfree(dev);
}
static int iris_hfi_validate_session(void *sess, const char *func)
diff --git a/drivers/media/platform/msm/cvp/cvp_hfi.h b/drivers/media/platform/msm/cvp/cvp_hfi.h
index 1b7c967..b8c5604 100644
--- a/drivers/media/platform/msm/cvp/cvp_hfi.h
+++ b/drivers/media/platform/msm/cvp/cvp_hfi.h
@@ -174,7 +174,7 @@ struct cvp_hfi_msg_sys_property_info_packet {
u32 size;
u32 packet_type;
u32 num_properties;
- u32 rg_property_data[1];
+ u32 rg_property_data[128];
};
enum session_flags {
@@ -188,11 +188,6 @@ struct cvp_hal_session {
void *device;
};
-struct cvp_hal_device_data {
- struct list_head dev_head;
- int dev_count;
-};
-
struct msm_cvp_fw {
void *cookie;
};
diff --git a/drivers/media/platform/msm/cvp/cvp_hfi_io.h b/drivers/media/platform/msm/cvp/cvp_hfi_io.h
index 83d9ab0..5fc4233 100644
--- a/drivers/media/platform/msm/cvp/cvp_hfi_io.h
+++ b/drivers/media/platform/msm/cvp/cvp_hfi_io.h
@@ -105,7 +105,7 @@
#define CVP_WRAPPER_INTR_CLEAR_A2H_BMSK 0x4
#define CVP_WRAPPER_INTR_CLEAR_A2H_SHFT 0x2
#define CVP_WRAPPER_CPU_STATUS (CVP_WRAPPER_TZ_BASE_OFFS + 0x10)
-#define CVP_WRAPPER_CPU_CLOCK_CONFIG (CVP_WRAPPER_TZ_BASE_OFFS + 0x0)
+#define CVP_WRAPPER_CPU_CLOCK_CONFIG (CVP_WRAPPER_TZ_BASE_OFFS + 0x50)
#define CVP_WRAPPER_CPU_CGC_DIS (CVP_WRAPPER_BASE_OFFS + 0x2010)
#define CVP_WRAPPER_DEBUG_BRIDGE_LPI_CONTROL (CVP_WRAPPER_BASE_OFFS + 0x54)
@@ -210,4 +210,7 @@
#define CVP_AON_WRAPPER_MVP_NOC_LPI_CONTROL (CVP_AON_BASE_OFFS)
#define CVP_AON_WRAPPER_MVP_NOC_LPI_STATUS (CVP_AON_BASE_OFFS + 0x4)
+#define CVP_CC_BASE_OFFS 0x000F0000
+#define CVP_CC_MVS0C_GDSCR (CVP_CC_BASE_OFFS + 0xBF8)
+#define CVP_CC_MVS1C_GDSCR (CVP_CC_BASE_OFFS + 0xC98)
#endif
diff --git a/drivers/media/platform/msm/cvp/hfi_packetization.c b/drivers/media/platform/msm/cvp/hfi_packetization.c
index 962689f..597c7cf 100644
--- a/drivers/media/platform/msm/cvp/hfi_packetization.c
+++ b/drivers/media/platform/msm/cvp/hfi_packetization.c
@@ -394,21 +394,21 @@ int cvp_create_pkt_cmd_session_send(
if (!out_pkt || !in_pkt || !session)
return -EINVAL;
+ if (ptr->size > MAX_HFI_PKT_SIZE * sizeof(unsigned int))
+ goto error_hfi_packet;
+
+ if (ptr->session_id != hash32_ptr(session))
+ goto error_hfi_packet;
+
def_idx = get_pkt_index(ptr);
- if (def_idx < 0 && ptr->size < MAX_HFI_PKT_SIZE * sizeof(u32)) {
+ if (def_idx < 0) {
memcpy(out_pkt, in_pkt, ptr->size);
return 0;
}
- if (ptr->size > MAX_HFI_PKT_SIZE * sizeof(unsigned int))
- goto error_hfi_packet;
-
if (cvp_hfi_defs[def_idx].type != ptr->packet_type)
goto error_hfi_packet;
- if (ptr->session_id != hash32_ptr(session))
- goto error_hfi_packet;
-
memcpy(out_pkt, in_pkt, ptr->size);
return 0;
diff --git a/drivers/media/platform/msm/cvp/hfi_response_handler.c b/drivers/media/platform/msm/cvp/hfi_response_handler.c
index 1782e9d..393ff3c 100644
--- a/drivers/media/platform/msm/cvp/hfi_response_handler.c
+++ b/drivers/media/platform/msm/cvp/hfi_response_handler.c
@@ -420,20 +420,32 @@ static struct msm_cvp_inst *cvp_get_inst_from_id(struct msm_cvp_core *core,
{
struct msm_cvp_inst *inst = NULL;
bool match = false;
+ int count = 0;
if (!core || !session_id)
return NULL;
- mutex_lock(&core->lock);
- list_for_each_entry(inst, &core->instances, list) {
- if (hash32_ptr(inst->session) == session_id) {
- match = true;
- break;
+retry:
+ if (mutex_trylock(&core->lock)) {
+ list_for_each_entry(inst, &core->instances, list) {
+ if (hash32_ptr(inst->session) == session_id) {
+ match = true;
+ break;
+ }
}
- }
- inst = match ? inst : NULL;
- mutex_unlock(&core->lock);
+ inst = match ? inst : NULL;
+ mutex_unlock(&core->lock);
+ } else {
+ if (core->state == CVP_CORE_UNINIT)
+ return NULL;
+ usleep_range(100, 200);
+ count++;
+ if (count < 1000)
+ goto retry;
+ else
+ dprintk(CVP_ERR, "timeout locking core mutex\n");
+ }
return inst;
@@ -677,9 +689,9 @@ static int hfi_process_sys_property_info(u32 device_id,
if (!pkt) {
dprintk(CVP_ERR, "%s: invalid param\n", __func__);
return -EINVAL;
- } else if (pkt->size < sizeof(*pkt)) {
+ } else if (pkt->size > sizeof(*pkt)) {
dprintk(CVP_ERR,
- "%s: bad_pkt_size\n", __func__);
+ "%s: bad_pkt_size %d\n", __func__, pkt->size);
return -E2BIG;
} else if (!pkt->num_properties) {
dprintk(CVP_WARN,
diff --git a/drivers/media/platform/msm/cvp/msm_cvp.c b/drivers/media/platform/msm/cvp/msm_cvp.c
index d283267..44aa779 100644
--- a/drivers/media/platform/msm/cvp/msm_cvp.c
+++ b/drivers/media/platform/msm/cvp/msm_cvp.c
@@ -584,7 +584,6 @@ static int msm_cvp_session_receive_hfi(struct msm_cvp_inst *inst,
if (wait_event_timeout(sq->wq,
_cvp_msg_pending(inst, sq, &msg), wait_time) == 0) {
dprintk(CVP_WARN, "session queue wait timeout\n");
- msm_cvp_comm_kill_session(inst);
rc = -ETIMEDOUT;
goto exit;
}
@@ -786,16 +785,6 @@ static int msm_cvp_session_process_hfi(
return -ECONNRESET;
inst->cur_cmd_type = CVP_KMD_SEND_CMD_PKT;
- sq = &inst->session_queue;
- spin_lock(&sq->lock);
- if (sq->state != QUEUE_ACTIVE) {
- spin_unlock(&sq->lock);
- dprintk(CVP_ERR, "%s: invalid queue state\n", __func__);
- rc = -EINVAL;
- goto exit;
- }
- spin_unlock(&sq->lock);
-
hdev = inst->core->device;
pkt_idx = get_pkt_index((struct cvp_hal_session_cmd_pkt *)in_pkt);
@@ -811,6 +800,18 @@ static int msm_cvp_session_process_hfi(
buf_num = cvp_hfi_defs[pkt_idx].buf_num;
signal = cvp_hfi_defs[pkt_idx].resp;
}
+ if (signal == HAL_NO_RESP) {
+ /* Frame packets are not allowed before session starts*/
+ sq = &inst->session_queue;
+ spin_lock(&sq->lock);
+ if (sq->state != QUEUE_ACTIVE) {
+ spin_unlock(&sq->lock);
+ dprintk(CVP_ERR, "%s: invalid queue state\n", __func__);
+ rc = -EINVAL;
+ goto exit;
+ }
+ spin_unlock(&sq->lock);
+ }
if (in_offset && in_buf_num) {
offset = in_offset;
@@ -1636,6 +1637,7 @@ static int msm_cvp_session_start(struct msm_cvp_inst *inst,
}
sq->state = QUEUE_ACTIVE;
spin_unlock(&sq->lock);
+
return 0;
}
diff --git a/drivers/media/platform/msm/cvp/msm_cvp_common.c b/drivers/media/platform/msm/cvp/msm_cvp_common.c
index cf412f9..ef3726a 100644
--- a/drivers/media/platform/msm/cvp/msm_cvp_common.c
+++ b/drivers/media/platform/msm/cvp/msm_cvp_common.c
@@ -23,11 +23,12 @@
static void handle_session_error(enum hal_command_response cmd, void *data);
-static void dump_hfi_queue_info(struct iris_hfi_device *device)
+static void dump_hfi_queue(struct iris_hfi_device *device)
{
struct cvp_hfi_queue_header *queue;
struct cvp_iface_q_info *qinfo;
int i;
+ u32 *read_ptr, read_idx;
dprintk(CVP_ERR, "HFI queues in order of cmd(rd, wr), msg and dbg:\n");
@@ -39,8 +40,21 @@ static void dump_hfi_queue_info(struct iris_hfi_device *device)
for (i = 0; i <= CVP_IFACEQ_DBGQ_IDX; i++) {
qinfo = &device->iface_queues[i];
queue = (struct cvp_hfi_queue_header *)qinfo->q_hdr;
+ if (!queue) {
+ dprintk(CVP_ERR, "HFI queue not init, fail to dump\n");
+ return;
+ }
dprintk(CVP_ERR, "queue details: %d %d\n",
queue->qhdr_read_idx, queue->qhdr_write_idx);
+ if (queue->qhdr_read_idx != queue->qhdr_write_idx) {
+ read_idx = queue->qhdr_read_idx;
+ read_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) +
+ (read_idx << 2));
+ dprintk(CVP_ERR, "queue payload: %x %x %x %x\n",
+ read_ptr[0], read_ptr[1],
+ read_ptr[2], read_ptr[3]);
+ }
+
}
}
@@ -383,7 +397,8 @@ int wait_for_sess_signal_receipt(struct msm_cvp_inst *inst,
if (!rc) {
dprintk(CVP_WARN, "Wait interrupted or timed out: %d\n",
SESSION_MSG_INDEX(cmd));
- msm_cvp_comm_kill_session(inst);
+ call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data);
+ dump_hfi_queue(hdev->hfi_device_data);
rc = -EIO;
} else {
rc = 0;
@@ -590,6 +605,7 @@ static void handle_sys_error(enum hal_command_response cmd, void *data)
struct msm_cvp_inst *inst = NULL;
int rc = 0;
unsigned long flags = 0;
+ enum cvp_core_state cur_state;
subsystem_crashed("cvpss");
if (!response) {
@@ -615,20 +631,24 @@ static void handle_sys_error(enum hal_command_response cmd, void *data)
return;
}
+ cur_state = core->state;
+ core->state = CVP_CORE_UNINIT;
dprintk(CVP_WARN, "SYS_ERROR received for core %pK\n", core);
msm_cvp_noc_error_info(core);
call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data);
list_for_each_entry(inst, &core->instances, list) {
dprintk(CVP_WARN,
- "%s: sys error for inst %#x kref %x, cmd %x\n",
+ "%s: sys error inst %#x kref %x, cmd %x state %x\n",
__func__, inst, kref_read(&inst->kref),
- inst->cur_cmd_type);
- change_cvp_inst_state(inst, MSM_CVP_CORE_INVALID);
-
- spin_lock_irqsave(&inst->event_handler.lock, flags);
- inst->event_handler.event = CVP_SSR_EVENT;
- spin_unlock_irqrestore(&inst->event_handler.lock, flags);
- wake_up_all(&inst->event_handler.wq);
+ inst->cur_cmd_type, inst->state);
+ if (inst->state != MSM_CVP_CORE_INVALID) {
+ change_cvp_inst_state(inst, MSM_CVP_CORE_INVALID);
+ spin_lock_irqsave(&inst->event_handler.lock, flags);
+ inst->event_handler.event = CVP_SSR_EVENT;
+ spin_unlock_irqrestore(
+ &inst->event_handler.lock, flags);
+ wake_up_all(&inst->event_handler.wq);
+ }
if (!core->trigger_ssr)
msm_cvp_comm_print_inst_info(inst);
@@ -645,10 +665,10 @@ static void handle_sys_error(enum hal_command_response cmd, void *data)
rc = call_hfi_op(hdev, core_release, hdev->hfi_device_data);
if (rc) {
dprintk(CVP_ERR, "core_release failed\n");
+ core->state = cur_state;
mutex_unlock(&core->lock);
return;
}
- core->state = CVP_CORE_UNINIT;
mutex_unlock(&core->lock);
dprintk(CVP_WARN, "SYS_ERROR handled.\n");
@@ -871,7 +891,7 @@ static int msm_comm_session_abort(struct msm_cvp_inst *inst)
dprintk(CVP_ERR, "%s: inst %pK session %x abort timed out\n",
__func__, inst, hash32_ptr(inst->session));
call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data);
- dump_hfi_queue_info(hdev->hfi_device_data);
+ dump_hfi_queue(hdev->hfi_device_data);
msm_cvp_comm_generate_sys_error(inst);
rc = -EBUSY;
} else {
@@ -941,6 +961,7 @@ void msm_cvp_comm_handle_thermal_event(void)
int msm_cvp_comm_check_core_init(struct msm_cvp_core *core)
{
int rc = 0;
+ struct cvp_hfi_device *hdev;
mutex_lock(&core->lock);
if (core->state >= CVP_CORE_INIT_DONE) {
@@ -955,6 +976,9 @@ int msm_cvp_comm_check_core_init(struct msm_cvp_core *core)
if (!rc) {
dprintk(CVP_ERR, "%s: Wait interrupted or timed out: %d\n",
__func__, SYS_MSG_INDEX(HAL_SYS_INIT_DONE));
+ hdev = core->device;
+ call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data);
+ dump_hfi_queue(hdev->hfi_device_data);
rc = -EIO;
goto exit;
} else {
@@ -1225,8 +1249,8 @@ int msm_cvp_comm_try_state(struct msm_cvp_inst *inst, int state)
if (inst->state == MSM_CVP_CORE_INVALID) {
dprintk(CVP_ERR, "%s: inst %pK is in invalid\n",
__func__, inst);
- rc = -EINVAL;
- goto exit;
+ mutex_unlock(&inst->sync_lock);
+ return -EINVAL;
}
flipped_state = get_flipped_state(inst->state, state);
@@ -1275,7 +1299,6 @@ int msm_cvp_comm_try_state(struct msm_cvp_inst *inst, int state)
break;
}
-exit:
mutex_unlock(&inst->sync_lock);
if (rc) {
@@ -1354,6 +1377,9 @@ void msm_cvp_ssr_handler(struct work_struct *work)
if (!s)
return;
+ call_hfi_op(hdev, flush_debug_queue,
+ hdev->hfi_device_data);
+ dump_hfi_queue(hdev->hfi_device_data);
msm_cvp_comm_kill_session(inst);
cvp_put_inst(s);
} else {
@@ -1453,7 +1479,7 @@ int msm_cvp_comm_kill_session(struct msm_cvp_inst *inst)
}
}
- if (inst->state == MSM_CVP_CORE_UNINIT) {
+ if (inst->state >= MSM_CVP_CORE_UNINIT) {
spin_lock_irqsave(&inst->event_handler.lock, flags);
inst->event_handler.event = CVP_SSR_EVENT;
spin_unlock_irqrestore(&inst->event_handler.lock, flags);
@@ -1714,6 +1740,12 @@ int cvp_comm_release_persist_buffers(struct msm_cvp_inst *inst)
mutex_unlock(&inst->persistbufs.lock);
return -EINVAL;
}
+ if (inst->state > MSM_CVP_CLOSE_DONE) {
+ list_del(&buf->list);
+ msm_cvp_smem_free(handle);
+ kfree(buf);
+ continue;
+ }
buffer_info.buffer_size = handle->size;
buffer_info.buffer_type = buf->buffer_type;
buffer_info.num_buffers = 1;
diff --git a/drivers/media/platform/msm/cvp/msm_cvp_debug.c b/drivers/media/platform/msm/cvp/msm_cvp_debug.c
index dbc7d98..063ef64 100644
--- a/drivers/media/platform/msm/cvp/msm_cvp_debug.c
+++ b/drivers/media/platform/msm/cvp/msm_cvp_debug.c
@@ -8,7 +8,7 @@
#include "msm_cvp_debug.h"
#include "cvp_hfi_api.h"
-int msm_cvp_debug = CVP_ERR | CVP_WARN;
+int msm_cvp_debug = CVP_ERR | CVP_WARN | CVP_FW;
EXPORT_SYMBOL(msm_cvp_debug);
int msm_cvp_debug_out = CVP_OUT_PRINTK;
diff --git a/drivers/media/platform/msm/cvp/msm_cvp_dsp.c b/drivers/media/platform/msm/cvp/msm_cvp_dsp.c
index 8dabdae..8218282 100644
--- a/drivers/media/platform/msm/cvp/msm_cvp_dsp.c
+++ b/drivers/media/platform/msm/cvp/msm_cvp_dsp.c
@@ -78,6 +78,7 @@ static int cvp_dsp_send_cmd(void *msg, uint32_t len)
int err = 0;
if (IS_ERR_OR_NULL(me->chan)) {
+ dprintk(CVP_ERR, "%s: DSP GLink is not ready\n", __func__);
err = -EINVAL;
goto bail;
}
@@ -211,6 +212,8 @@ int cvp_dsp_send_cmd_hfi_queue(phys_addr_t *phys_addr,
dprintk(CVP_ERR,
"%s: Incorrect DDR type value %d\n",
__func__, local_cmd_msg.ddr_type);
+ err = -EINVAL;
+ goto exit;
}
mutex_lock(&me->smd_mutex);
@@ -219,7 +222,7 @@ int cvp_dsp_send_cmd_hfi_queue(phys_addr_t *phys_addr,
mutex_unlock(&me->smd_mutex);
dprintk(CVP_DBG,
- "%s :: address of buffer, PA=0x%pK size_buff=%d ddr_type=%d\n",
+ "%s: address of buffer, PA=0x%pK size_buff=%d ddr_type=%d\n",
__func__, phys_addr, size_in_bytes, local_cmd_msg.ddr_type);
err = hyp_assign_phys((uint64_t)local_cmd_msg.msg_ptr,
@@ -229,33 +232,34 @@ int cvp_dsp_send_cmd_hfi_queue(phys_addr_t *phys_addr,
dprintk(CVP_ERR,
"%s: Failed in hyp_assign. err=%d\n",
__func__, err);
- return err;
+ goto exit;
}
err = cvp_dsp_send_cmd
(&local_cmd_msg, sizeof(struct cvp_dsp_cmd_msg));
- if (err != 0)
+ if (err) {
dprintk(CVP_ERR,
- "%s: cvp_dsp_send_cmd failed with err=%d\n",
+ "%s: cvp_dsp_send_cmd faidmesgled with err=%d\n",
__func__, err);
- else {
- core = list_first_entry(&cvp_driver->cores,
- struct msm_cvp_core, list);
- timeout = msecs_to_jiffies(
- core->resources.msm_cvp_dsp_rsp_timeout);
- err = wait_for_completion_timeout(
- &me->cmdqueue_send_work, timeout);
- if (!err) {
- dprintk(CVP_ERR, "failed to send cmdqueue\n");
- return -ETIMEDOUT;
- }
-
- mutex_lock(&me->smd_mutex);
- me->cvp_shutdown = STATUS_OK;
- me->cdsp_state = STATUS_OK;
- mutex_unlock(&me->smd_mutex);
+ goto exit;
}
+ core = list_first_entry(&cvp_driver->cores,
+ struct msm_cvp_core, list);
+ timeout = msecs_to_jiffies(
+ core->resources.msm_cvp_dsp_rsp_timeout);
+ if (!wait_for_completion_timeout(&me->cmdqueue_send_work, timeout)) {
+ dprintk(CVP_ERR, "failed to send cmdqueue\n");
+ err = -ETIMEDOUT;
+ goto exit;
+ }
+
+ mutex_lock(&me->smd_mutex);
+ me->cvp_shutdown = STATUS_OK;
+ me->cdsp_state = STATUS_OK;
+ mutex_unlock(&me->smd_mutex);
+
+exit:
return err;
}
diff --git a/drivers/media/platform/msm/cvp/msm_cvp_internal.h b/drivers/media/platform/msm/cvp/msm_cvp_internal.h
index 0d5b18c..139b322 100644
--- a/drivers/media/platform/msm/cvp/msm_cvp_internal.h
+++ b/drivers/media/platform/msm/cvp/msm_cvp_internal.h
@@ -28,7 +28,7 @@
#define MAX_SUPPORTED_INSTANCES 16
#define MAX_NAME_LENGTH 64
#define MAX_DEBUGFS_NAME 50
-#define DCVS_FTB_WINDOW 16
+#define MAX_DSP_INIT_ATTEMPTS 16
#define SYS_MSG_START HAL_SYS_INIT_DONE
#define SYS_MSG_END HAL_SYS_ERROR
diff --git a/drivers/media/platform/msm/cvp/msm_cvp_platform.c b/drivers/media/platform/msm/cvp/msm_cvp_platform.c
index 2f3eff7..8579ead 100644
--- a/drivers/media/platform/msm/cvp/msm_cvp_platform.c
+++ b/drivers/media/platform/msm/cvp/msm_cvp_platform.c
@@ -142,8 +142,10 @@ void *cvp_get_drv_data(struct device *dev)
match = of_match_node(msm_cvp_dt_match, dev->of_node);
- if (match)
- driver_data = (struct msm_cvp_platform_data *)match->data;
+ if (!match)
+ return NULL;
+
+ driver_data = (struct msm_cvp_platform_data *)match->data;
if (!strcmp(match->compatible, "qcom,kona-cvp")) {
ddr_type = of_fdt_get_ddrtype();
diff --git a/drivers/media/platform/msm/npu/npu_dbg.c b/drivers/media/platform/msm/npu/npu_dbg.c
index f69efe5..d81ffa1 100644
--- a/drivers/media/platform/msm/npu/npu_dbg.c
+++ b/drivers/media/platform/msm/npu/npu_dbg.c
@@ -103,6 +103,13 @@ static void npu_dump_all_ipc_queue(struct npu_device *npu_dev)
void npu_dump_debug_info(struct npu_device *npu_dev)
{
+ struct npu_host_ctx *host_ctx = &npu_dev->host_ctx;
+
+ if (host_ctx->fw_state != FW_ENABLED) {
+ NPU_WARN("NPU is disabled\n");
+ return;
+ }
+
npu_dump_debug_timeout_stats(npu_dev);
npu_dump_dbg_registers(npu_dev);
npu_dump_all_ipc_queue(npu_dev);
diff --git a/drivers/media/platform/msm/npu/npu_dev.c b/drivers/media/platform/msm/npu/npu_dev.c
index 732a9df..b54bdeb 100644
--- a/drivers/media/platform/msm/npu/npu_dev.c
+++ b/drivers/media/platform/msm/npu/npu_dev.c
@@ -74,14 +74,10 @@ static int npu_get_info(struct npu_client *client, unsigned long arg);
static int npu_map_buf(struct npu_client *client, unsigned long arg);
static int npu_unmap_buf(struct npu_client *client,
unsigned long arg);
-static int npu_load_network(struct npu_client *client,
- unsigned long arg);
static int npu_load_network_v2(struct npu_client *client,
unsigned long arg);
static int npu_unload_network(struct npu_client *client,
unsigned long arg);
-static int npu_exec_network(struct npu_client *client,
- unsigned long arg);
static int npu_exec_network_v2(struct npu_client *client,
unsigned long arg);
static int npu_receive_event(struct npu_client *client,
@@ -126,8 +122,6 @@ static const char * const npu_exclude_rate_clocks[] = {
"axi_clk",
"ahb_clk",
"dma_clk",
- "llm_temp_clk",
- "llm_curr_clk",
"atb_clk",
"s2p_clk",
};
@@ -1095,38 +1089,6 @@ static int npu_unmap_buf(struct npu_client *client, unsigned long arg)
return 0;
}
-static int npu_load_network(struct npu_client *client,
- unsigned long arg)
-{
- struct msm_npu_load_network_ioctl req;
- struct msm_npu_unload_network_ioctl unload_req;
- void __user *argp = (void __user *)arg;
- int ret = 0;
-
- ret = copy_from_user(&req, argp, sizeof(req));
-
- if (ret) {
- NPU_ERR("fail to copy from user\n");
- return -EFAULT;
- }
-
- NPU_DBG("network load with perf request %d\n", req.perf_mode);
-
- ret = npu_host_load_network(client, &req);
- if (ret) {
- NPU_ERR("npu_host_load_network failed %d\n", ret);
- return ret;
- }
-
- ret = copy_to_user(argp, &req, sizeof(req));
- if (ret) {
- NPU_ERR("fail to copy to user\n");
- ret = -EFAULT;
- unload_req.network_hdl = req.network_hdl;
- npu_host_unload_network(client, &unload_req);
- }
- return ret;
-}
static int npu_load_network_v2(struct npu_client *client,
unsigned long arg)
@@ -1216,44 +1178,6 @@ static int npu_unload_network(struct npu_client *client,
return 0;
}
-static int npu_exec_network(struct npu_client *client,
- unsigned long arg)
-{
- struct msm_npu_exec_network_ioctl req;
- void __user *argp = (void __user *)arg;
- int ret = 0;
-
- ret = copy_from_user(&req, argp, sizeof(req));
-
- if (ret) {
- NPU_ERR("fail to copy from user\n");
- return -EFAULT;
- }
-
- if ((req.input_layer_num > MSM_NPU_MAX_INPUT_LAYER_NUM) ||
- (req.output_layer_num > MSM_NPU_MAX_OUTPUT_LAYER_NUM)) {
- NPU_ERR("Invalid input/out layer num %d[max:%d] %d[max:%d]\n",
- req.input_layer_num, MSM_NPU_MAX_INPUT_LAYER_NUM,
- req.output_layer_num, MSM_NPU_MAX_OUTPUT_LAYER_NUM);
- return -EINVAL;
- }
-
- ret = npu_host_exec_network(client, &req);
-
- if (ret) {
- NPU_ERR("npu_host_exec_network failed %d\n", ret);
- return ret;
- }
-
- ret = copy_to_user(argp, &req, sizeof(req));
-
- if (ret) {
- NPU_ERR("fail to copy to user\n");
- return -EFAULT;
- }
- return 0;
-}
-
static int npu_exec_network_v2(struct npu_client *client,
unsigned long arg)
{
@@ -1446,7 +1370,8 @@ static long npu_ioctl(struct file *file, unsigned int cmd,
ret = npu_unmap_buf(client, arg);
break;
case MSM_NPU_LOAD_NETWORK:
- ret = npu_load_network(client, arg);
+ NPU_ERR("npu_load_network_v1 is no longer supported\n");
+ ret = -ENOTTY;
break;
case MSM_NPU_LOAD_NETWORK_V2:
ret = npu_load_network_v2(client, arg);
@@ -1455,7 +1380,8 @@ static long npu_ioctl(struct file *file, unsigned int cmd,
ret = npu_unload_network(client, arg);
break;
case MSM_NPU_EXEC_NETWORK:
- ret = npu_exec_network(client, arg);
+ NPU_ERR("npu_exec_network_v1 is no longer supported\n");
+ ret = -ENOTTY;
break;
case MSM_NPU_EXEC_NETWORK_V2:
ret = npu_exec_network_v2(client, arg);
diff --git a/drivers/media/platform/msm/npu/npu_mgr.c b/drivers/media/platform/msm/npu/npu_mgr.c
index 4c19a24..cf449af 100644
--- a/drivers/media/platform/msm/npu/npu_mgr.c
+++ b/drivers/media/platform/msm/npu/npu_mgr.c
@@ -732,6 +732,7 @@ static int host_error_hdlr(struct npu_device *npu_dev, bool force)
if (host_ctx->wdg_irq_sts) {
NPU_INFO("watchdog irq triggered\n");
+ npu_dump_debug_info(npu_dev);
fw_alive = false;
}
@@ -861,8 +862,10 @@ static void npu_disable_fw_work(struct work_struct *work)
npu_dev = container_of(host_ctx, struct npu_device, host_ctx);
mutex_lock(&host_ctx->lock);
- disable_fw_nolock(npu_dev);
- host_ctx->bridge_mbox_pwr_on = false;
+ if (host_ctx->bridge_mbox_pwr_on) {
+ disable_fw_nolock(npu_dev);
+ host_ctx->bridge_mbox_pwr_on = false;
+ }
mutex_unlock(&host_ctx->lock);
NPU_DBG("Exit disable fw work\n");
}
@@ -897,6 +900,12 @@ static void npu_bridge_mbox_work(struct work_struct *work)
return;
}
+ if ((host_ctx->wdg_irq_sts != 0) || (host_ctx->err_irq_sts != 0)) {
+ NPU_WARN("SSR is triggered, skip this time\n");
+ mutex_unlock(&host_ctx->lock);
+ return;
+ }
+
/* queue or modify delayed work to disable fw */
mod_delayed_work(host_ctx->wq, &host_ctx->disable_fw_work,
NPU_MBOX_IDLE_TIMEOUT);
@@ -1544,28 +1553,6 @@ static int npu_send_misc_cmd(struct npu_device *npu_dev, uint32_t q_idx,
return ret;
}
-static void host_copy_patch_data(struct npu_patch_tuple *param, uint32_t value,
- struct msm_npu_layer *layer_info)
-{
- param->value = value;
- param->chunk_id = layer_info->patch_info.chunk_id;
- param->loc_offset = layer_info->patch_info.loc_offset;
- param->instruction_size_in_bytes =
- layer_info->patch_info.instruction_size_in_bytes;
- param->shift_value_in_bits =
- layer_info->patch_info.shift_value_in_bits;
- param->variable_size_in_bits =
- layer_info->patch_info.variable_size_in_bits;
-
- NPU_DBG("copy_patch_data: %x %d %x %x %x %x\n",
- param->value,
- param->chunk_id,
- param->loc_offset,
- param->instruction_size_in_bytes,
- param->shift_value_in_bits,
- param->variable_size_in_bits);
-}
-
static void host_copy_patch_data_v2(struct npu_patch_tuple_v2 *param,
struct msm_npu_patch_info_v2 *patch_info)
{
@@ -1625,110 +1612,6 @@ static int set_perf_mode(struct npu_device *npu_dev)
return ret;
}
-int32_t npu_host_load_network(struct npu_client *client,
- struct msm_npu_load_network_ioctl *load_ioctl)
-{
- int ret = 0;
- struct npu_device *npu_dev = client->npu_dev;
- struct npu_network *network;
- struct ipc_cmd_load_pkt load_packet;
- struct npu_host_ctx *host_ctx = &npu_dev->host_ctx;
-
- ret = enable_fw(npu_dev);
- if (ret)
- return ret;
-
- mutex_lock(&host_ctx->lock);
- network = alloc_network(host_ctx, client);
- if (!network) {
- ret = -ENOMEM;
- goto err_deinit_fw;
- }
-
- network_get(network);
- network->buf_hdl = load_ioctl->buf_ion_hdl;
- network->size = load_ioctl->buf_size;
- network->phy_add = load_ioctl->buf_phys_addr;
- network->first_block_size = load_ioctl->first_block_size;
- network->priority = load_ioctl->priority;
- network->perf_mode = load_ioctl->perf_mode;
-
- /* verify mapped physical address */
- if (!npu_mem_verify_addr(client, network->phy_add)) {
- ret = -EINVAL;
- goto error_free_network;
- }
-
- ret = set_perf_mode(npu_dev);
- if (ret) {
- NPU_ERR("set_perf_mode failed\n");
- goto error_free_network;
- }
-
- load_packet.header.cmd_type = NPU_IPC_CMD_LOAD;
- load_packet.header.size = sizeof(struct ipc_cmd_load_pkt);
- load_packet.header.trans_id =
- atomic_add_return(1, &host_ctx->ipc_trans_id);
- load_packet.header.flags = load_ioctl->flags;
-
- /* ACO Buffer. Use the npu mapped aco address */
- load_packet.buf_pkt.address = (uint64_t)network->phy_add;
- load_packet.buf_pkt.buf_size = network->first_block_size;
- load_packet.buf_pkt.network_id = network->id;
-
- /* NPU_IPC_CMD_LOAD will go onto IPC_QUEUE_APPS_EXEC */
- reinit_completion(&network->cmd_done);
- ret = npu_send_network_cmd(npu_dev, network, &load_packet, false,
- false);
- if (ret) {
- NPU_ERR("NPU_IPC_CMD_LOAD sent failed: %d\n", ret);
- goto error_free_network;
- }
-
- mutex_unlock(&host_ctx->lock);
-
- ret = wait_for_completion_interruptible_timeout(
- &network->cmd_done,
- (host_ctx->fw_dbg_mode & FW_DBG_MODE_INC_TIMEOUT) ?
- NW_DEBUG_TIMEOUT : NW_CMD_TIMEOUT);
-
- mutex_lock(&host_ctx->lock);
- if (!ret) {
- NPU_ERR("NPU_IPC_CMD_LOAD time out\n");
- npu_dump_debug_info(npu_dev);
- ret = -ETIMEDOUT;
- goto error_free_network;
- } else if (ret < 0) {
- NPU_ERR("NPU_IPC_CMD_LOAD is interrupted by signal\n");
- goto error_free_network;
- }
-
- if (network->fw_error) {
- ret = -EIO;
- NPU_ERR("fw is in error state during load network\n");
- goto error_free_network;
- }
-
- ret = network->cmd_ret_status;
- if (ret)
- goto error_free_network;
-
- load_ioctl->network_hdl = network->network_hdl;
- network->is_active = true;
- network_put(network);
- mutex_unlock(&host_ctx->lock);
-
- return ret;
-
-error_free_network:
- network_put(network);
- free_network(host_ctx, client, network->id);
-err_deinit_fw:
- mutex_unlock(&host_ctx->lock);
- disable_fw(npu_dev);
- return ret;
-}
-
int32_t npu_host_load_network_v2(struct npu_client *client,
struct msm_npu_load_network_ioctl_v2 *load_ioctl,
struct msm_npu_patch_info_v2 *patch_info)
@@ -1969,131 +1852,6 @@ int32_t npu_host_unload_network(struct npu_client *client,
return ret;
}
-int32_t npu_host_exec_network(struct npu_client *client,
- struct msm_npu_exec_network_ioctl *exec_ioctl)
-{
- struct npu_device *npu_dev = client->npu_dev;
- struct ipc_cmd_execute_pkt exec_packet;
- /* npu mapped addr */
- uint64_t input_off, output_off;
- int32_t ret;
- struct npu_network *network;
- struct npu_host_ctx *host_ctx = &npu_dev->host_ctx;
- bool async_ioctl = !!exec_ioctl->async;
-
- mutex_lock(&host_ctx->lock);
- network = get_network_by_hdl(host_ctx, client,
- exec_ioctl->network_hdl);
-
- if (!network) {
- mutex_unlock(&host_ctx->lock);
- return -EINVAL;
- }
-
- if (!network->is_active) {
- NPU_ERR("network is not active\n");
- ret = -EINVAL;
- goto exec_done;
- }
-
- if (network->fw_error) {
- NPU_ERR("fw is in error state\n");
- ret = -EIO;
- goto exec_done;
- }
-
- NPU_DBG("execute network %lld\n", network->id);
- memset(&exec_packet, 0, sizeof(exec_packet));
- if (exec_ioctl->patching_required) {
- if ((exec_ioctl->input_layer_num != 1) ||
- (exec_ioctl->output_layer_num != 1)) {
- NPU_ERR("Invalid input/output layer num\n");
- ret = -EINVAL;
- goto exec_done;
- }
-
- input_off = exec_ioctl->input_layers[0].buf_phys_addr;
- output_off = exec_ioctl->output_layers[0].buf_phys_addr;
- /* verify mapped physical address */
- if (!npu_mem_verify_addr(client, input_off) ||
- !npu_mem_verify_addr(client, output_off)) {
- NPU_ERR("Invalid patch buf address\n");
- ret = -EINVAL;
- goto exec_done;
- }
-
- exec_packet.patch_params.num_params = 2;
- host_copy_patch_data(&exec_packet.patch_params.param[0],
- (uint32_t)input_off, &exec_ioctl->input_layers[0]);
- host_copy_patch_data(&exec_packet.patch_params.param[1],
- (uint32_t)output_off, &exec_ioctl->output_layers[0]);
- } else {
- exec_packet.patch_params.num_params = 0;
- }
-
- exec_packet.header.cmd_type = NPU_IPC_CMD_EXECUTE;
- exec_packet.header.size = sizeof(struct ipc_cmd_execute_pkt);
- exec_packet.header.trans_id =
- atomic_add_return(1, &host_ctx->ipc_trans_id);
- exec_packet.header.flags = 0xF;
- exec_packet.network_hdl = network->network_hdl;
-
- /* Send it on the high priority queue */
- reinit_completion(&network->cmd_done);
- ret = npu_send_network_cmd(npu_dev, network, &exec_packet, async_ioctl,
- false);
-
- if (ret) {
- NPU_ERR("NPU_IPC_CMD_EXECUTE sent failed: %d\n", ret);
- goto exec_done;
- }
-
- if (async_ioctl) {
- NPU_DBG("Async ioctl, return now\n");
- goto exec_done;
- }
-
- mutex_unlock(&host_ctx->lock);
-
- ret = wait_for_completion_timeout(
- &network->cmd_done,
- (host_ctx->fw_dbg_mode & FW_DBG_MODE_INC_TIMEOUT) ?
- NW_DEBUG_TIMEOUT : NW_CMD_TIMEOUT);
-
- mutex_lock(&host_ctx->lock);
- if (!ret) {
- NPU_ERR("npu: %x NPU_IPC_CMD_EXECUTE time out\n",
- network->id);
- npu_dump_debug_info(npu_dev);
- network->cmd_pending = false;
- ret = -ETIMEDOUT;
- goto exec_done;
- }
-
- if (network->fw_error) {
- ret = -EIO;
- NPU_ERR("fw is in error state during execute network\n");
- } else {
- ret = network->cmd_ret_status;
- NPU_DBG("execution status %d\n", ret);
- }
-
-exec_done:
- network_put(network);
- mutex_unlock(&host_ctx->lock);
-
- /*
- * treat network execution timed out as error in order to
- * force npu fw to stop execution
- */
- if (ret == -ETIMEDOUT) {
- NPU_ERR("Error handling after execution failure\n");
- host_error_hdlr(npu_dev, true);
- }
-
- return ret;
-}
-
int32_t npu_host_exec_network_v2(struct npu_client *client,
struct msm_npu_exec_network_ioctl_v2 *exec_ioctl,
struct msm_npu_patch_buf_info *patch_buf_info)
diff --git a/drivers/media/platform/msm/npu/npu_mgr.h b/drivers/media/platform/msm/npu/npu_mgr.h
index 36bcc08..6c14720 100644
--- a/drivers/media/platform/msm/npu/npu_mgr.h
+++ b/drivers/media/platform/msm/npu/npu_mgr.h
@@ -131,15 +131,11 @@ int32_t npu_host_map_buf(struct npu_client *client,
struct msm_npu_map_buf_ioctl *map_ioctl);
int32_t npu_host_unmap_buf(struct npu_client *client,
struct msm_npu_unmap_buf_ioctl *unmap_ioctl);
-int32_t npu_host_load_network(struct npu_client *client,
- struct msm_npu_load_network_ioctl *load_ioctl);
int32_t npu_host_load_network_v2(struct npu_client *client,
struct msm_npu_load_network_ioctl_v2 *load_ioctl,
struct msm_npu_patch_info_v2 *patch_info);
int32_t npu_host_unload_network(struct npu_client *client,
struct msm_npu_unload_network_ioctl *unload);
-int32_t npu_host_exec_network(struct npu_client *client,
- struct msm_npu_exec_network_ioctl *exec_ioctl);
int32_t npu_host_exec_network_v2(struct npu_client *client,
struct msm_npu_exec_network_ioctl_v2 *exec_ioctl,
struct msm_npu_patch_buf_info *patch_buf_info);
diff --git a/drivers/media/platform/rcar_fdp1.c b/drivers/media/platform/rcar_fdp1.c
index 2a15b7c..0d14670 100644
--- a/drivers/media/platform/rcar_fdp1.c
+++ b/drivers/media/platform/rcar_fdp1.c
@@ -257,6 +257,8 @@ MODULE_PARM_DESC(debug, "activate debug info");
#define FD1_IP_H3_ES1 0x02010101
#define FD1_IP_M3W 0x02010202
#define FD1_IP_H3 0x02010203
+#define FD1_IP_M3N 0x02010204
+#define FD1_IP_E3 0x02010205
/* LUTs */
#define FD1_LUT_DIF_ADJ 0x1000
@@ -2365,6 +2367,12 @@ static int fdp1_probe(struct platform_device *pdev)
case FD1_IP_H3:
dprintk(fdp1, "FDP1 Version R-Car H3\n");
break;
+ case FD1_IP_M3N:
+ dprintk(fdp1, "FDP1 Version R-Car M3N\n");
+ break;
+ case FD1_IP_E3:
+ dprintk(fdp1, "FDP1 Version R-Car E3\n");
+ break;
default:
dev_err(fdp1->dev, "FDP1 Unidentifiable (0x%08x)\n",
hw_version);
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c
index ca11f8a..4b8516c 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c
@@ -527,7 +527,8 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx,
dev);
ctx->mv_count = s5p_mfc_hw_call(dev->mfc_ops, get_mv_count,
dev);
- ctx->scratch_buf_size = s5p_mfc_hw_call(dev->mfc_ops,
+ if (FW_HAS_E_MIN_SCRATCH_BUF(dev))
+ ctx->scratch_buf_size = s5p_mfc_hw_call(dev->mfc_ops,
get_min_scratch_buf_size, dev);
if (ctx->img_width == 0 || ctx->img_height == 0)
ctx->state = MFCINST_ERROR;
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
index eb85ced..5e080f3 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
@@ -38,6 +38,11 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev)
for (i = 0; i < pm->num_clocks; i++) {
pm->clocks[i] = devm_clk_get(pm->device, pm->clk_names[i]);
if (IS_ERR(pm->clocks[i])) {
+ /* additional clocks are optional */
+ if (i && PTR_ERR(pm->clocks[i]) == -ENOENT) {
+ pm->clocks[i] = NULL;
+ continue;
+ }
mfc_err("Failed to get clock: %s\n",
pm->clk_names[i]);
return PTR_ERR(pm->clocks[i]);
diff --git a/drivers/media/platform/vimc/vimc-capture.c b/drivers/media/platform/vimc/vimc-capture.c
index 65d657d..8e014cc 100644
--- a/drivers/media/platform/vimc/vimc-capture.c
+++ b/drivers/media/platform/vimc/vimc-capture.c
@@ -132,12 +132,15 @@ static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct vimc_cap_device *vcap = video_drvdata(file);
+ int ret;
/* Do not change the format while stream is on */
if (vb2_is_busy(&vcap->queue))
return -EBUSY;
- vimc_cap_try_fmt_vid_cap(file, priv, f);
+ ret = vimc_cap_try_fmt_vid_cap(file, priv, f);
+ if (ret)
+ return ret;
dev_dbg(vcap->dev, "%s: format update: "
"old:%dx%d (0x%x, %d, %d, %d, %d) "
diff --git a/drivers/media/radio/radio-raremono.c b/drivers/media/radio/radio-raremono.c
index 9a5079d..729600c 100644
--- a/drivers/media/radio/radio-raremono.c
+++ b/drivers/media/radio/radio-raremono.c
@@ -271,6 +271,14 @@ static int vidioc_g_frequency(struct file *file, void *priv,
return 0;
}
+static void raremono_device_release(struct v4l2_device *v4l2_dev)
+{
+ struct raremono_device *radio = to_raremono_dev(v4l2_dev);
+
+ kfree(radio->buffer);
+ kfree(radio);
+}
+
/* File system interface */
static const struct v4l2_file_operations usb_raremono_fops = {
.owner = THIS_MODULE,
@@ -295,12 +303,14 @@ static int usb_raremono_probe(struct usb_interface *intf,
struct raremono_device *radio;
int retval = 0;
- radio = devm_kzalloc(&intf->dev, sizeof(struct raremono_device), GFP_KERNEL);
- if (radio)
- radio->buffer = devm_kmalloc(&intf->dev, BUFFER_LENGTH, GFP_KERNEL);
-
- if (!radio || !radio->buffer)
+ radio = kzalloc(sizeof(*radio), GFP_KERNEL);
+ if (!radio)
return -ENOMEM;
+ radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
+ if (!radio->buffer) {
+ kfree(radio);
+ return -ENOMEM;
+ }
radio->usbdev = interface_to_usbdev(intf);
radio->intf = intf;
@@ -324,7 +334,8 @@ static int usb_raremono_probe(struct usb_interface *intf,
if (retval != 3 ||
(get_unaligned_be16(&radio->buffer[1]) & 0xfff) == 0x0242) {
dev_info(&intf->dev, "this is not Thanko's Raremono.\n");
- return -ENODEV;
+ retval = -ENODEV;
+ goto free_mem;
}
dev_info(&intf->dev, "Thanko's Raremono connected: (%04X:%04X)\n",
@@ -333,7 +344,7 @@ static int usb_raremono_probe(struct usb_interface *intf,
retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
if (retval < 0) {
dev_err(&intf->dev, "couldn't register v4l2_device\n");
- return retval;
+ goto free_mem;
}
mutex_init(&radio->lock);
@@ -345,6 +356,7 @@ static int usb_raremono_probe(struct usb_interface *intf,
radio->vdev.ioctl_ops = &usb_raremono_ioctl_ops;
radio->vdev.lock = &radio->lock;
radio->vdev.release = video_device_release_empty;
+ radio->v4l2_dev.release = raremono_device_release;
usb_set_intfdata(intf, &radio->v4l2_dev);
@@ -360,6 +372,10 @@ static int usb_raremono_probe(struct usb_interface *intf,
}
dev_err(&intf->dev, "could not register video device\n");
v4l2_device_unregister(&radio->v4l2_dev);
+
+free_mem:
+ kfree(radio->buffer);
+ kfree(radio);
return retval;
}
diff --git a/drivers/media/radio/rtc6226/radio-rtc6226-common.c b/drivers/media/radio/rtc6226/radio-rtc6226-common.c
index 15cf8c8..7b8750a 100644
--- a/drivers/media/radio/rtc6226/radio-rtc6226-common.c
+++ b/drivers/media/radio/rtc6226/radio-rtc6226-common.c
@@ -1389,9 +1389,9 @@ int rtc6226_power_up(struct rtc6226_device *radio)
FMDBG("%s : after initialization\n", __func__);
/* mpxconfig */
- /* Disable Softmute / Disable Mute / De-emphasis / Volume 8 */
- radio->registers[MPXCFG] = 0x0008 |
- MPXCFG_CSR0_DIS_SMUTE | MPXCFG_CSR0_DIS_MUTE |
+ /* Disable Mute / De-emphasis / Volume 12 */
+ radio->registers[MPXCFG] = 0x000c |
+ MPXCFG_CSR0_DIS_MUTE |
((de << 12) & MPXCFG_CSR0_DEEM);
retval = rtc6226_set_register(radio, MPXCFG);
if (retval < 0)
diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c
index dccdf65..33abc86 100644
--- a/drivers/media/radio/wl128x/fmdrv_v4l2.c
+++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c
@@ -549,6 +549,7 @@ int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr)
/* Register with V4L2 subsystem as RADIO device */
if (video_register_device(&gradio_dev, VFL_TYPE_RADIO, radio_nr)) {
+ v4l2_device_unregister(&fmdev->v4l2_dev);
fmerr("Could not register video device\n");
return -ENOMEM;
}
@@ -562,6 +563,8 @@ int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr)
if (ret < 0) {
fmerr("(fmdev): Can't init ctrl handler\n");
v4l2_ctrl_handler_free(&fmdev->ctrl_handler);
+ video_unregister_device(fmdev->radio_dev);
+ v4l2_device_unregister(&fmdev->v4l2_dev);
return -EBUSY;
}
diff --git a/drivers/media/rc/ir-spi.c b/drivers/media/rc/ir-spi.c
index 66334e8..c58f2d3 100644
--- a/drivers/media/rc/ir-spi.c
+++ b/drivers/media/rc/ir-spi.c
@@ -161,6 +161,7 @@ static const struct of_device_id ir_spi_of_match[] = {
{ .compatible = "ir-spi-led" },
{},
};
+MODULE_DEVICE_TABLE(of, ir_spi_of_match);
static struct spi_driver ir_spi_driver = {
.probe = ir_spi_probe,
diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c
index 257ae0d..e3f6329 100644
--- a/drivers/media/usb/au0828/au0828-core.c
+++ b/drivers/media/usb/au0828/au0828-core.c
@@ -623,6 +623,12 @@ static int au0828_usb_probe(struct usb_interface *interface,
/* Setup */
au0828_card_setup(dev);
+ /*
+ * Store the pointer to the au0828_dev so it can be accessed in
+ * au0828_usb_disconnect
+ */
+ usb_set_intfdata(interface, dev);
+
/* Analog TV */
retval = au0828_analog_register(dev, interface);
if (retval) {
@@ -641,12 +647,6 @@ static int au0828_usb_probe(struct usb_interface *interface,
/* Remote controller */
au0828_rc_register(dev);
- /*
- * Store the pointer to the au0828_dev so it can be accessed in
- * au0828_usb_disconnect
- */
- usb_set_intfdata(interface, dev);
-
pr_info("Registered device AU0828 [%s]\n",
dev->board.name == NULL ? "Unset" : dev->board.name);
diff --git a/drivers/media/usb/cpia2/cpia2_usb.c b/drivers/media/usb/cpia2/cpia2_usb.c
index a771e0a..f5b0459 100644
--- a/drivers/media/usb/cpia2/cpia2_usb.c
+++ b/drivers/media/usb/cpia2/cpia2_usb.c
@@ -902,7 +902,6 @@ static void cpia2_usb_disconnect(struct usb_interface *intf)
cpia2_unregister_camera(cam);
v4l2_device_disconnect(&cam->v4l2_dev);
mutex_unlock(&cam->v4l2_lock);
- v4l2_device_put(&cam->v4l2_dev);
if(cam->buffers) {
DBG("Wakeup waiting processes\n");
@@ -911,6 +910,8 @@ static void cpia2_usb_disconnect(struct usb_interface *intf)
wake_up_interruptible(&cam->wq_stream);
}
+ v4l2_device_put(&cam->v4l2_dev);
+
LOG("CPiA2 camera disconnected.\n");
}
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-init.c b/drivers/media/usb/dvb-usb/dvb-usb-init.c
index 40ca4ea..39ac224 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-init.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-init.c
@@ -287,12 +287,15 @@ EXPORT_SYMBOL(dvb_usb_device_init);
void dvb_usb_device_exit(struct usb_interface *intf)
{
struct dvb_usb_device *d = usb_get_intfdata(intf);
- const char *name = "generic DVB-USB module";
+ const char *default_name = "generic DVB-USB module";
+ char name[40];
usb_set_intfdata(intf, NULL);
if (d != NULL && d->desc != NULL) {
- name = d->desc->name;
+ strscpy(name, d->desc->name, sizeof(name));
dvb_usb_exit(d);
+ } else {
+ strscpy(name, default_name, sizeof(name));
}
info("%s successfully deinitialized and disconnected.", name);
diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c
index 1b89c77..0615996 100644
--- a/drivers/media/usb/hdpvr/hdpvr-video.c
+++ b/drivers/media/usb/hdpvr/hdpvr-video.c
@@ -439,7 +439,7 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
/* wait for the first buffer */
if (!(file->f_flags & O_NONBLOCK)) {
if (wait_event_interruptible(dev->wait_data,
- hdpvr_get_next_buffer(dev)))
+ !list_empty_careful(&dev->rec_buff_list)))
return -ERESTARTSYS;
}
@@ -465,10 +465,17 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
goto err;
}
if (!err) {
- v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev,
- "timeout: restart streaming\n");
+ v4l2_info(&dev->v4l2_dev,
+ "timeout: restart streaming\n");
+ mutex_lock(&dev->io_mutex);
hdpvr_stop_streaming(dev);
- msecs_to_jiffies(4000);
+ mutex_unlock(&dev->io_mutex);
+ /*
+ * The FW needs about 4 seconds after streaming
+ * stopped before it is ready to restart
+ * streaming.
+ */
+ msleep(4000);
err = hdpvr_start_streaming(dev);
if (err) {
ret = err;
@@ -1133,9 +1140,7 @@ static void hdpvr_device_release(struct video_device *vdev)
struct hdpvr_device *dev = video_get_drvdata(vdev);
hdpvr_delete(dev);
- mutex_lock(&dev->io_mutex);
flush_work(&dev->worker);
- mutex_unlock(&dev->io_mutex);
v4l2_device_unregister(&dev->v4l2_dev);
v4l2_ctrl_handler_free(&dev->hdl);
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
index 673fdca..fcb201a 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
@@ -1680,7 +1680,7 @@ static int pvr2_decoder_enable(struct pvr2_hdw *hdw,int enablefl)
}
if (!hdw->flag_decoder_missed) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "WARNING: No decoder present");
+ "***WARNING*** No decoder present");
hdw->flag_decoder_missed = !0;
trace_stbit("flag_decoder_missed",
hdw->flag_decoder_missed);
@@ -2366,7 +2366,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
if (hdw_desc->flag_is_experimental) {
pvr2_trace(PVR2_TRACE_INFO, "**********");
pvr2_trace(PVR2_TRACE_INFO,
- "WARNING: Support for this device (%s) is experimental.",
+ "***WARNING*** Support for this device (%s) is experimental.",
hdw_desc->description);
pvr2_trace(PVR2_TRACE_INFO,
"Important functionality might not be entirely working.");
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c
index f3003ca..922c062 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c
@@ -343,11 +343,11 @@ static int i2c_hack_cx25840(struct pvr2_hdw *hdw,
if ((ret != 0) || (*rdata == 0x04) || (*rdata == 0x0a)) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "WARNING: Detected a wedged cx25840 chip; the device will not work.");
+ "***WARNING*** Detected a wedged cx25840 chip; the device will not work.");
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "WARNING: Try power cycling the pvrusb2 device.");
+ "***WARNING*** Try power cycling the pvrusb2 device.");
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "WARNING: Disabling further access to the device to prevent other foul-ups.");
+ "***WARNING*** Disabling further access to the device to prevent other foul-ups.");
// This blocks all further communication with the part.
hdw->i2c_func[0x44] = NULL;
pvr2_hdw_render_useless(hdw);
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-std.c b/drivers/media/usb/pvrusb2/pvrusb2-std.c
index 6b651f8..37dc299 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-std.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-std.c
@@ -353,7 +353,7 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
bcnt = pvr2_std_id_to_str(buf,sizeof(buf),fmsk);
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
- "WARNING: Failed to classify the following standard(s): %.*s",
+ "***WARNING*** Failed to classify the following standard(s): %.*s",
bcnt,buf);
}
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 4e2e42c..5357558 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -2353,7 +2353,9 @@ void uvc_ctrl_cleanup_device(struct uvc_device *dev)
struct uvc_entity *entity;
unsigned int i;
- cancel_work_sync(&dev->async_ctrl.work);
+ /* Can be uninitialized if we are aborting on probe error. */
+ if (dev->async_ctrl.work.func)
+ cancel_work_sync(&dev->async_ctrl.work);
/* Free controls and control mappings for all entities. */
list_for_each_entry(entity, &dev->entities, list) {
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 78d0fa0..e9ea261 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -2260,16 +2260,15 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
v4l2_ctrl_fill(cfg->id, &name, &type, &min, &max, &step,
&def, &flags);
- is_menu = (cfg->type == V4L2_CTRL_TYPE_MENU ||
- cfg->type == V4L2_CTRL_TYPE_INTEGER_MENU);
+ is_menu = (type == V4L2_CTRL_TYPE_MENU ||
+ type == V4L2_CTRL_TYPE_INTEGER_MENU);
if (is_menu)
WARN_ON(step);
else
WARN_ON(cfg->menu_skip_mask);
- if (cfg->type == V4L2_CTRL_TYPE_MENU && qmenu == NULL)
+ if (type == V4L2_CTRL_TYPE_MENU && !qmenu) {
qmenu = v4l2_ctrl_get_menu(cfg->id);
- else if (cfg->type == V4L2_CTRL_TYPE_INTEGER_MENU &&
- qmenu_int == NULL) {
+ } else if (type == V4L2_CTRL_TYPE_INTEGER_MENU && !qmenu_int) {
handler_set_err(hdl, -EINVAL);
return NULL;
}
diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c
index 1246d69..b1564ca 100644
--- a/drivers/memstick/core/memstick.c
+++ b/drivers/memstick/core/memstick.c
@@ -629,13 +629,18 @@ static int __init memstick_init(void)
return -ENOMEM;
rc = bus_register(&memstick_bus_type);
- if (!rc)
- rc = class_register(&memstick_host_class);
+ if (rc)
+ goto error_destroy_workqueue;
- if (!rc)
- return 0;
+ rc = class_register(&memstick_host_class);
+ if (rc)
+ goto error_bus_unregister;
+ return 0;
+
+error_bus_unregister:
bus_unregister(&memstick_bus_type);
+error_destroy_workqueue:
destroy_workqueue(workqueue);
return rc;
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
index 5f1e37d..47d6d40 100644
--- a/drivers/mfd/arizona-core.c
+++ b/drivers/mfd/arizona-core.c
@@ -996,7 +996,7 @@ int arizona_dev_init(struct arizona *arizona)
unsigned int reg, val;
int (*apply_patch)(struct arizona *) = NULL;
const struct mfd_cell *subdevs = NULL;
- int n_subdevs, ret, i;
+ int n_subdevs = 0, ret, i;
dev_set_drvdata(arizona->dev, arizona);
mutex_init(&arizona->clk_lock);
diff --git a/drivers/mfd/hi655x-pmic.c b/drivers/mfd/hi655x-pmic.c
index 96c07fa..6693f74 100644
--- a/drivers/mfd/hi655x-pmic.c
+++ b/drivers/mfd/hi655x-pmic.c
@@ -112,6 +112,8 @@ static int hi655x_pmic_probe(struct platform_device *pdev)
pmic->regmap = devm_regmap_init_mmio_clk(dev, NULL, base,
&hi655x_regmap_config);
+ if (IS_ERR(pmic->regmap))
+ return PTR_ERR(pmic->regmap);
regmap_read(pmic->regmap, HI655X_BUS_ADDR(HI655X_VER_REG), &pmic->ver);
if ((pmic->ver < PMU_VER_START) || (pmic->ver > PMU_VER_END)) {
diff --git a/drivers/mfd/madera-core.c b/drivers/mfd/madera-core.c
index 8cfea96..45c7d8b 100644
--- a/drivers/mfd/madera-core.c
+++ b/drivers/mfd/madera-core.c
@@ -278,6 +278,7 @@ const struct of_device_id madera_of_match[] = {
{ .compatible = "cirrus,wm1840", .data = (void *)WM1840 },
{}
};
+MODULE_DEVICE_TABLE(of, madera_of_match);
EXPORT_SYMBOL_GPL(madera_of_match);
static int madera_get_reset_gpio(struct madera *madera)
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
index 94e3f32c..182973d 100644
--- a/drivers/mfd/mfd-core.c
+++ b/drivers/mfd/mfd-core.c
@@ -179,6 +179,7 @@ static int mfd_add_device(struct device *parent, int id,
for_each_child_of_node(parent->of_node, np) {
if (of_device_is_compatible(np, cell->of_compatible)) {
pdev->dev.of_node = np;
+ pdev->dev.fwnode = &np->fwnode;
break;
}
}
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index ddfcf4a..dc35376 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -724,7 +724,7 @@ static int at24_probe(struct i2c_client *client)
nvmem_config.name = dev_name(dev);
nvmem_config.dev = dev;
nvmem_config.read_only = !writable;
- nvmem_config.root_only = true;
+ nvmem_config.root_only = !(pdata.flags & AT24_FLAG_IRUGO);
nvmem_config.owner = THIS_MODULE;
nvmem_config.compat = true;
nvmem_config.base_dev = dev;
diff --git a/drivers/misc/lkdtm/Makefile b/drivers/misc/lkdtm/Makefile
index 390de73..939651b 100644
--- a/drivers/misc/lkdtm/Makefile
+++ b/drivers/misc/lkdtm/Makefile
@@ -14,8 +14,7 @@
OBJCOPYFLAGS :=
OBJCOPYFLAGS_rodata_objcopy.o := \
- --set-section-flags .text=alloc,readonly \
- --rename-section .text=.rodata
+ --rename-section .text=.rodata,alloc,readonly,load
targets += rodata.o rodata_objcopy.o
$(obj)/rodata_objcopy.o: $(obj)/rodata.o FORCE
$(call if_changed,objcopy)
diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h
index bb1ee98..225373e 100644
--- a/drivers/misc/mei/hw-me-regs.h
+++ b/drivers/misc/mei/hw-me-regs.h
@@ -141,6 +141,9 @@
#define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */
+#define MEI_DEV_ID_MCC 0x4B70 /* Mule Creek Canyon (EHL) */
+#define MEI_DEV_ID_MCC_4 0x4B75 /* Mule Creek Canyon 4 (EHL) */
+
/*
* MEI HW Section
*/
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
index 4299658..a66ebce 100644
--- a/drivers/misc/mei/pci-me.c
+++ b/drivers/misc/mei/pci-me.c
@@ -107,6 +107,9 @@ static const struct pci_device_id mei_me_pci_tbl[] = {
{MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)},
+ {MEI_PCI_DEVICE(MEI_DEV_ID_MCC, MEI_ME_PCH12_CFG)},
+ {MEI_PCI_DEVICE(MEI_DEV_ID_MCC_4, MEI_ME_PCH8_CFG)},
+
/* required last entry */
{0, }
};
diff --git a/drivers/misc/vmw_vmci/vmci_context.c b/drivers/misc/vmw_vmci/vmci_context.c
index 21d0fa5..bc089e6 100644
--- a/drivers/misc/vmw_vmci/vmci_context.c
+++ b/drivers/misc/vmw_vmci/vmci_context.c
@@ -29,6 +29,9 @@
#include "vmci_driver.h"
#include "vmci_event.h"
+/* Use a wide upper bound for the maximum contexts. */
+#define VMCI_MAX_CONTEXTS 2000
+
/*
* List of current VMCI contexts. Contexts can be added by
* vmci_ctx_create() and removed via vmci_ctx_destroy().
@@ -125,19 +128,22 @@ struct vmci_ctx *vmci_ctx_create(u32 cid, u32 priv_flags,
/* Initialize host-specific VMCI context. */
init_waitqueue_head(&context->host_context.wait_queue);
- context->queue_pair_array = vmci_handle_arr_create(0);
+ context->queue_pair_array =
+ vmci_handle_arr_create(0, VMCI_MAX_GUEST_QP_COUNT);
if (!context->queue_pair_array) {
error = -ENOMEM;
goto err_free_ctx;
}
- context->doorbell_array = vmci_handle_arr_create(0);
+ context->doorbell_array =
+ vmci_handle_arr_create(0, VMCI_MAX_GUEST_DOORBELL_COUNT);
if (!context->doorbell_array) {
error = -ENOMEM;
goto err_free_qp_array;
}
- context->pending_doorbell_array = vmci_handle_arr_create(0);
+ context->pending_doorbell_array =
+ vmci_handle_arr_create(0, VMCI_MAX_GUEST_DOORBELL_COUNT);
if (!context->pending_doorbell_array) {
error = -ENOMEM;
goto err_free_db_array;
@@ -212,7 +218,7 @@ static int ctx_fire_notification(u32 context_id, u32 priv_flags)
* We create an array to hold the subscribers we find when
* scanning through all contexts.
*/
- subscriber_array = vmci_handle_arr_create(0);
+ subscriber_array = vmci_handle_arr_create(0, VMCI_MAX_CONTEXTS);
if (subscriber_array == NULL)
return VMCI_ERROR_NO_MEM;
@@ -631,20 +637,26 @@ int vmci_ctx_add_notification(u32 context_id, u32 remote_cid)
spin_lock(&context->lock);
- list_for_each_entry(n, &context->notifier_list, node) {
- if (vmci_handle_is_equal(n->handle, notifier->handle)) {
- exists = true;
- break;
+ if (context->n_notifiers < VMCI_MAX_CONTEXTS) {
+ list_for_each_entry(n, &context->notifier_list, node) {
+ if (vmci_handle_is_equal(n->handle, notifier->handle)) {
+ exists = true;
+ break;
+ }
}
- }
- if (exists) {
- kfree(notifier);
- result = VMCI_ERROR_ALREADY_EXISTS;
+ if (exists) {
+ kfree(notifier);
+ result = VMCI_ERROR_ALREADY_EXISTS;
+ } else {
+ list_add_tail_rcu(¬ifier->node,
+ &context->notifier_list);
+ context->n_notifiers++;
+ result = VMCI_SUCCESS;
+ }
} else {
- list_add_tail_rcu(¬ifier->node, &context->notifier_list);
- context->n_notifiers++;
- result = VMCI_SUCCESS;
+ kfree(notifier);
+ result = VMCI_ERROR_NO_MEM;
}
spin_unlock(&context->lock);
@@ -729,8 +741,7 @@ static int vmci_ctx_get_chkpt_doorbells(struct vmci_ctx *context,
u32 *buf_size, void **pbuf)
{
struct dbell_cpt_state *dbells;
- size_t n_doorbells;
- int i;
+ u32 i, n_doorbells;
n_doorbells = vmci_handle_arr_get_size(context->doorbell_array);
if (n_doorbells > 0) {
@@ -868,7 +879,8 @@ int vmci_ctx_rcv_notifications_get(u32 context_id,
spin_lock(&context->lock);
*db_handle_array = context->pending_doorbell_array;
- context->pending_doorbell_array = vmci_handle_arr_create(0);
+ context->pending_doorbell_array =
+ vmci_handle_arr_create(0, VMCI_MAX_GUEST_DOORBELL_COUNT);
if (!context->pending_doorbell_array) {
context->pending_doorbell_array = *db_handle_array;
*db_handle_array = NULL;
@@ -950,12 +962,11 @@ int vmci_ctx_dbell_create(u32 context_id, struct vmci_handle handle)
return VMCI_ERROR_NOT_FOUND;
spin_lock(&context->lock);
- if (!vmci_handle_arr_has_entry(context->doorbell_array, handle)) {
- vmci_handle_arr_append_entry(&context->doorbell_array, handle);
- result = VMCI_SUCCESS;
- } else {
+ if (!vmci_handle_arr_has_entry(context->doorbell_array, handle))
+ result = vmci_handle_arr_append_entry(&context->doorbell_array,
+ handle);
+ else
result = VMCI_ERROR_DUPLICATE_ENTRY;
- }
spin_unlock(&context->lock);
vmci_ctx_put(context);
@@ -1091,15 +1102,16 @@ int vmci_ctx_notify_dbell(u32 src_cid,
if (!vmci_handle_arr_has_entry(
dst_context->pending_doorbell_array,
handle)) {
- vmci_handle_arr_append_entry(
+ result = vmci_handle_arr_append_entry(
&dst_context->pending_doorbell_array,
handle);
-
- ctx_signal_notify(dst_context);
- wake_up(&dst_context->host_context.wait_queue);
-
+ if (result == VMCI_SUCCESS) {
+ ctx_signal_notify(dst_context);
+ wake_up(&dst_context->host_context.wait_queue);
+ }
+ } else {
+ result = VMCI_SUCCESS;
}
- result = VMCI_SUCCESS;
}
spin_unlock(&dst_context->lock);
}
@@ -1126,13 +1138,11 @@ int vmci_ctx_qp_create(struct vmci_ctx *context, struct vmci_handle handle)
if (context == NULL || vmci_handle_is_invalid(handle))
return VMCI_ERROR_INVALID_ARGS;
- if (!vmci_handle_arr_has_entry(context->queue_pair_array, handle)) {
- vmci_handle_arr_append_entry(&context->queue_pair_array,
- handle);
- result = VMCI_SUCCESS;
- } else {
+ if (!vmci_handle_arr_has_entry(context->queue_pair_array, handle))
+ result = vmci_handle_arr_append_entry(
+ &context->queue_pair_array, handle);
+ else
result = VMCI_ERROR_DUPLICATE_ENTRY;
- }
return result;
}
diff --git a/drivers/misc/vmw_vmci/vmci_handle_array.c b/drivers/misc/vmw_vmci/vmci_handle_array.c
index 344973a..917e18a 100644
--- a/drivers/misc/vmw_vmci/vmci_handle_array.c
+++ b/drivers/misc/vmw_vmci/vmci_handle_array.c
@@ -16,24 +16,29 @@
#include <linux/slab.h>
#include "vmci_handle_array.h"
-static size_t handle_arr_calc_size(size_t capacity)
+static size_t handle_arr_calc_size(u32 capacity)
{
- return sizeof(struct vmci_handle_arr) +
+ return VMCI_HANDLE_ARRAY_HEADER_SIZE +
capacity * sizeof(struct vmci_handle);
}
-struct vmci_handle_arr *vmci_handle_arr_create(size_t capacity)
+struct vmci_handle_arr *vmci_handle_arr_create(u32 capacity, u32 max_capacity)
{
struct vmci_handle_arr *array;
+ if (max_capacity == 0 || capacity > max_capacity)
+ return NULL;
+
if (capacity == 0)
- capacity = VMCI_HANDLE_ARRAY_DEFAULT_SIZE;
+ capacity = min((u32)VMCI_HANDLE_ARRAY_DEFAULT_CAPACITY,
+ max_capacity);
array = kmalloc(handle_arr_calc_size(capacity), GFP_ATOMIC);
if (!array)
return NULL;
array->capacity = capacity;
+ array->max_capacity = max_capacity;
array->size = 0;
return array;
@@ -44,27 +49,34 @@ void vmci_handle_arr_destroy(struct vmci_handle_arr *array)
kfree(array);
}
-void vmci_handle_arr_append_entry(struct vmci_handle_arr **array_ptr,
- struct vmci_handle handle)
+int vmci_handle_arr_append_entry(struct vmci_handle_arr **array_ptr,
+ struct vmci_handle handle)
{
struct vmci_handle_arr *array = *array_ptr;
if (unlikely(array->size >= array->capacity)) {
/* reallocate. */
struct vmci_handle_arr *new_array;
- size_t new_capacity = array->capacity * VMCI_ARR_CAP_MULT;
- size_t new_size = handle_arr_calc_size(new_capacity);
+ u32 capacity_bump = min(array->max_capacity - array->capacity,
+ array->capacity);
+ size_t new_size = handle_arr_calc_size(array->capacity +
+ capacity_bump);
+
+ if (array->size >= array->max_capacity)
+ return VMCI_ERROR_NO_MEM;
new_array = krealloc(array, new_size, GFP_ATOMIC);
if (!new_array)
- return;
+ return VMCI_ERROR_NO_MEM;
- new_array->capacity = new_capacity;
+ new_array->capacity += capacity_bump;
*array_ptr = array = new_array;
}
array->entries[array->size] = handle;
array->size++;
+
+ return VMCI_SUCCESS;
}
/*
@@ -74,7 +86,7 @@ struct vmci_handle vmci_handle_arr_remove_entry(struct vmci_handle_arr *array,
struct vmci_handle entry_handle)
{
struct vmci_handle handle = VMCI_INVALID_HANDLE;
- size_t i;
+ u32 i;
for (i = 0; i < array->size; i++) {
if (vmci_handle_is_equal(array->entries[i], entry_handle)) {
@@ -109,7 +121,7 @@ struct vmci_handle vmci_handle_arr_remove_tail(struct vmci_handle_arr *array)
* Handle at given index, VMCI_INVALID_HANDLE if invalid index.
*/
struct vmci_handle
-vmci_handle_arr_get_entry(const struct vmci_handle_arr *array, size_t index)
+vmci_handle_arr_get_entry(const struct vmci_handle_arr *array, u32 index)
{
if (unlikely(index >= array->size))
return VMCI_INVALID_HANDLE;
@@ -120,7 +132,7 @@ vmci_handle_arr_get_entry(const struct vmci_handle_arr *array, size_t index)
bool vmci_handle_arr_has_entry(const struct vmci_handle_arr *array,
struct vmci_handle entry_handle)
{
- size_t i;
+ u32 i;
for (i = 0; i < array->size; i++)
if (vmci_handle_is_equal(array->entries[i], entry_handle))
diff --git a/drivers/misc/vmw_vmci/vmci_handle_array.h b/drivers/misc/vmw_vmci/vmci_handle_array.h
index b5f3a7f..0fc5859 100644
--- a/drivers/misc/vmw_vmci/vmci_handle_array.h
+++ b/drivers/misc/vmw_vmci/vmci_handle_array.h
@@ -17,32 +17,41 @@
#define _VMCI_HANDLE_ARRAY_H_
#include <linux/vmw_vmci_defs.h>
+#include <linux/limits.h>
#include <linux/types.h>
-#define VMCI_HANDLE_ARRAY_DEFAULT_SIZE 4
-#define VMCI_ARR_CAP_MULT 2 /* Array capacity multiplier */
-
struct vmci_handle_arr {
- size_t capacity;
- size_t size;
+ u32 capacity;
+ u32 max_capacity;
+ u32 size;
+ u32 pad;
struct vmci_handle entries[];
};
-struct vmci_handle_arr *vmci_handle_arr_create(size_t capacity);
+#define VMCI_HANDLE_ARRAY_HEADER_SIZE \
+ offsetof(struct vmci_handle_arr, entries)
+/* Select a default capacity that results in a 64 byte sized array */
+#define VMCI_HANDLE_ARRAY_DEFAULT_CAPACITY 6
+/* Make sure that the max array size can be expressed by a u32 */
+#define VMCI_HANDLE_ARRAY_MAX_CAPACITY \
+ ((U32_MAX - VMCI_HANDLE_ARRAY_HEADER_SIZE - 1) / \
+ sizeof(struct vmci_handle))
+
+struct vmci_handle_arr *vmci_handle_arr_create(u32 capacity, u32 max_capacity);
void vmci_handle_arr_destroy(struct vmci_handle_arr *array);
-void vmci_handle_arr_append_entry(struct vmci_handle_arr **array_ptr,
- struct vmci_handle handle);
+int vmci_handle_arr_append_entry(struct vmci_handle_arr **array_ptr,
+ struct vmci_handle handle);
struct vmci_handle vmci_handle_arr_remove_entry(struct vmci_handle_arr *array,
struct vmci_handle
entry_handle);
struct vmci_handle vmci_handle_arr_remove_tail(struct vmci_handle_arr *array);
struct vmci_handle
-vmci_handle_arr_get_entry(const struct vmci_handle_arr *array, size_t index);
+vmci_handle_arr_get_entry(const struct vmci_handle_arr *array, u32 index);
bool vmci_handle_arr_has_entry(const struct vmci_handle_arr *array,
struct vmci_handle entry_handle);
struct vmci_handle *vmci_handle_arr_get_handles(struct vmci_handle_arr *array);
-static inline size_t vmci_handle_arr_get_size(
+static inline u32 vmci_handle_arr_get_size(
const struct vmci_handle_arr *array)
{
return array->size;
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 80dc2fd..942da07 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -2038,8 +2038,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
* delayed. Allowing the transfer to take place
* avoids races and keeps things simple.
*/
- if ((err != -ETIMEDOUT) &&
- (cmd->opcode == MMC_SEND_TUNING_BLOCK)) {
+ if (err != -ETIMEDOUT) {
state = STATE_SENDING_DATA;
continue;
}
diff --git a/drivers/mmc/host/meson-mx-sdio.c b/drivers/mmc/host/meson-mx-sdio.c
index 9841b44..f6c76be 100644
--- a/drivers/mmc/host/meson-mx-sdio.c
+++ b/drivers/mmc/host/meson-mx-sdio.c
@@ -76,7 +76,7 @@
#define MESON_MX_SDIO_IRQC_IF_CONFIG_MASK GENMASK(7, 6)
#define MESON_MX_SDIO_IRQC_FORCE_DATA_CLK BIT(8)
#define MESON_MX_SDIO_IRQC_FORCE_DATA_CMD BIT(9)
- #define MESON_MX_SDIO_IRQC_FORCE_DATA_DAT_MASK GENMASK(10, 13)
+ #define MESON_MX_SDIO_IRQC_FORCE_DATA_DAT_MASK GENMASK(13, 10)
#define MESON_MX_SDIO_IRQC_SOFT_RESET BIT(15)
#define MESON_MX_SDIO_IRQC_FORCE_HALT BIT(30)
#define MESON_MX_SDIO_IRQC_HALT_HOLE BIT(31)
diff --git a/drivers/mmc/host/sdhci-pci-o2micro.c b/drivers/mmc/host/sdhci-pci-o2micro.c
index fa8d9da..e248d79 100644
--- a/drivers/mmc/host/sdhci-pci-o2micro.c
+++ b/drivers/mmc/host/sdhci-pci-o2micro.c
@@ -290,11 +290,21 @@ int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot)
{
struct sdhci_pci_chip *chip;
struct sdhci_host *host;
- u32 reg;
+ u32 reg, caps;
int ret;
chip = slot->chip;
host = slot->host;
+
+ caps = sdhci_readl(host, SDHCI_CAPABILITIES);
+
+ /*
+ * mmc_select_bus_width() will test the bus to determine the actual bus
+ * width.
+ */
+ if (caps & SDHCI_CAN_DO_8BIT)
+ host->mmc->caps |= MMC_CAP_8_BIT_DATA;
+
switch (chip->pdev->device) {
case PCI_DEVICE_ID_O2_SDS0:
case PCI_DEVICE_ID_O2_SEABIRD0:
diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c
index 57b5ed1..dce5b7e 100644
--- a/drivers/mtd/nand/raw/mtk_nand.c
+++ b/drivers/mtd/nand/raw/mtk_nand.c
@@ -509,7 +509,8 @@ static int mtk_nfc_setup_data_interface(struct mtd_info *mtd, int csline,
{
struct mtk_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd));
const struct nand_sdr_timings *timings;
- u32 rate, tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt;
+ u32 rate, tpoecs, tprecs, tc2r, tw2r, twh, twst = 0, trlt = 0;
+ u32 thold;
timings = nand_get_sdr_timings(conf);
if (IS_ERR(timings))
@@ -545,11 +546,28 @@ static int mtk_nfc_setup_data_interface(struct mtd_info *mtd, int csline,
twh = DIV_ROUND_UP(twh * rate, 1000000) - 1;
twh &= 0xf;
- twst = timings->tWP_min / 1000;
+ /* Calculate real WE#/RE# hold time in nanosecond */
+ thold = (twh + 1) * 1000000 / rate;
+ /* nanosecond to picosecond */
+ thold *= 1000;
+
+ /*
+ * WE# low level time should be expaned to meet WE# pulse time
+ * and WE# cycle time at the same time.
+ */
+ if (thold < timings->tWC_min)
+ twst = timings->tWC_min - thold;
+ twst = max(timings->tWP_min, twst) / 1000;
twst = DIV_ROUND_UP(twst * rate, 1000000) - 1;
twst &= 0xf;
- trlt = max(timings->tREA_max, timings->tRP_min) / 1000;
+ /*
+ * RE# low level time should be expaned to meet RE# pulse time,
+ * RE# access time and RE# cycle time at the same time.
+ */
+ if (thold < timings->tRC_min)
+ trlt = timings->tRC_min - thold;
+ trlt = max3(trlt, timings->tREA_max, timings->tRP_min) / 1000;
trlt = DIV_ROUND_UP(trlt * rate, 1000000) - 1;
trlt &= 0xf;
diff --git a/drivers/mtd/nand/raw/nand_micron.c b/drivers/mtd/nand/raw/nand_micron.c
index f5dc0a7..fb401c2 100644
--- a/drivers/mtd/nand/raw/nand_micron.c
+++ b/drivers/mtd/nand/raw/nand_micron.c
@@ -400,6 +400,14 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip)
(chip->id.data[4] & MICRON_ID_INTERNAL_ECC_MASK) != 0x2)
return MICRON_ON_DIE_UNSUPPORTED;
+ /*
+ * It seems that there are devices which do not support ECC officially.
+ * At least the MT29F2G08ABAGA / MT29F2G08ABBGA devices supports
+ * enabling the ECC feature but don't reflect that to the READ_ID table.
+ * So we have to guarantee that we disable the ECC feature directly
+ * after we did the READ_ID table command. Later we can evaluate the
+ * ECC_ENABLE support.
+ */
ret = micron_nand_on_die_ecc_setup(chip, true);
if (ret)
return MICRON_ON_DIE_UNSUPPORTED;
@@ -408,13 +416,13 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip)
if (ret)
return MICRON_ON_DIE_UNSUPPORTED;
- if (!(id[4] & MICRON_ID_ECC_ENABLED))
- return MICRON_ON_DIE_UNSUPPORTED;
-
ret = micron_nand_on_die_ecc_setup(chip, false);
if (ret)
return MICRON_ON_DIE_UNSUPPORTED;
+ if (!(id[4] & MICRON_ID_ECC_ENABLED))
+ return MICRON_ON_DIE_UNSUPPORTED;
+
ret = nand_readid_op(chip, 0, id, sizeof(id));
if (ret)
return MICRON_ON_DIE_UNSUPPORTED;
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 8c7bf91..48b3ab2 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -572,12 +572,12 @@ static int spinand_mtd_read(struct mtd_info *mtd, loff_t from,
if (ret == -EBADMSG) {
ecc_failed = true;
mtd->ecc_stats.failed++;
- ret = 0;
} else {
mtd->ecc_stats.corrected += ret;
max_bitflips = max_t(unsigned int, max_bitflips, ret);
}
+ ret = 0;
ops->retlen += iter.req.datalen;
ops->oobretlen += iter.req.ooblen;
}
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 7e162ff..be0b785 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3852,8 +3852,8 @@ static netdev_tx_t bond_xmit_roundrobin(struct sk_buff *skb,
struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
- struct iphdr *iph = ip_hdr(skb);
struct slave *slave;
+ int slave_cnt;
u32 slave_id;
/* Start with the curr_active_slave that joined the bond as the
@@ -3862,23 +3862,32 @@ static netdev_tx_t bond_xmit_roundrobin(struct sk_buff *skb,
* send the join/membership reports. The curr_active_slave found
* will send all of this type of traffic.
*/
- if (iph->protocol == IPPROTO_IGMP && skb->protocol == htons(ETH_P_IP)) {
- slave = rcu_dereference(bond->curr_active_slave);
- if (slave)
- bond_dev_queue_xmit(bond, skb, slave->dev);
- else
- bond_xmit_slave_id(bond, skb, 0);
- } else {
- int slave_cnt = READ_ONCE(bond->slave_cnt);
+ if (skb->protocol == htons(ETH_P_IP)) {
+ int noff = skb_network_offset(skb);
+ struct iphdr *iph;
- if (likely(slave_cnt)) {
- slave_id = bond_rr_gen_slave_id(bond);
- bond_xmit_slave_id(bond, skb, slave_id % slave_cnt);
- } else {
- bond_tx_drop(bond_dev, skb);
+ if (unlikely(!pskb_may_pull(skb, noff + sizeof(*iph))))
+ goto non_igmp;
+
+ iph = ip_hdr(skb);
+ if (iph->protocol == IPPROTO_IGMP) {
+ slave = rcu_dereference(bond->curr_active_slave);
+ if (slave)
+ bond_dev_queue_xmit(bond, skb, slave->dev);
+ else
+ bond_xmit_slave_id(bond, skb, 0);
+ return NETDEV_TX_OK;
}
}
+non_igmp:
+ slave_cnt = READ_ONCE(bond->slave_cnt);
+ if (likely(slave_cnt)) {
+ slave_id = bond_rr_gen_slave_id(bond);
+ bond_xmit_slave_id(bond, skb, slave_id % slave_cnt);
+ } else {
+ bond_tx_drop(bond_dev, skb);
+ }
return NETDEV_TX_OK;
}
diff --git a/drivers/net/caif/caif_hsi.c b/drivers/net/caif/caif_hsi.c
index 433a14b..253a1bb 100644
--- a/drivers/net/caif/caif_hsi.c
+++ b/drivers/net/caif/caif_hsi.c
@@ -1455,7 +1455,7 @@ static void __exit cfhsi_exit_module(void)
rtnl_lock();
list_for_each_safe(list_node, n, &cfhsi_list) {
cfhsi = list_entry(list_node, struct cfhsi, list);
- unregister_netdev(cfhsi->ndev);
+ unregister_netdevice(cfhsi->ndev);
}
rtnl_unlock();
}
diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c
index 9b44940..deb274a 100644
--- a/drivers/net/can/m_can/m_can.c
+++ b/drivers/net/can/m_can/m_can.c
@@ -822,6 +822,27 @@ static int m_can_poll(struct napi_struct *napi, int quota)
if (!irqstatus)
goto end;
+ /* Errata workaround for issue "Needless activation of MRAF irq"
+ * During frame reception while the MCAN is in Error Passive state
+ * and the Receive Error Counter has the value MCAN_ECR.REC = 127,
+ * it may happen that MCAN_IR.MRAF is set although there was no
+ * Message RAM access failure.
+ * If MCAN_IR.MRAF is enabled, an interrupt to the Host CPU is generated
+ * The Message RAM Access Failure interrupt routine needs to check
+ * whether MCAN_ECR.RP = ’1’ and MCAN_ECR.REC = 127.
+ * In this case, reset MCAN_IR.MRAF. No further action is required.
+ */
+ if ((priv->version <= 31) && (irqstatus & IR_MRAF) &&
+ (m_can_read(priv, M_CAN_ECR) & ECR_RP)) {
+ struct can_berr_counter bec;
+
+ __m_can_get_berr_counter(dev, &bec);
+ if (bec.rxerr == 127) {
+ m_can_write(priv, M_CAN_IR, IR_MRAF);
+ irqstatus &= ~IR_MRAF;
+ }
+ }
+
psr = m_can_read(priv, M_CAN_PSR);
if (irqstatus & IR_ERR_STATE)
work_done += m_can_handle_state_errors(dev, psr);
diff --git a/drivers/net/can/spi/Kconfig b/drivers/net/can/spi/Kconfig
index 8f2e0dd..792e9c6 100644
--- a/drivers/net/can/spi/Kconfig
+++ b/drivers/net/can/spi/Kconfig
@@ -8,9 +8,10 @@
Driver for the Holt HI311x SPI CAN controllers.
config CAN_MCP251X
- tristate "Microchip MCP251x SPI CAN controllers"
+ tristate "Microchip MCP251x and MCP25625 SPI CAN controllers"
depends on HAS_DMA
---help---
- Driver for the Microchip MCP251x SPI CAN controllers.
+ Driver for the Microchip MCP251x and MCP25625 SPI CAN
+ controllers.
endmenu
diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c
index e908176..da64e71 100644
--- a/drivers/net/can/spi/mcp251x.c
+++ b/drivers/net/can/spi/mcp251x.c
@@ -1,5 +1,5 @@
/*
- * CAN bus driver for Microchip 251x CAN Controller with SPI Interface
+ * CAN bus driver for Microchip 251x/25625 CAN Controller with SPI Interface
*
* MCP2510 support and bug fixes by Christian Pellegrin
* <chripell@evolware.org>
@@ -41,7 +41,7 @@
* static struct spi_board_info spi_board_info[] = {
* {
* .modalias = "mcp2510",
- * // or "mcp2515" depending on your controller
+ * // "mcp2515" or "mcp25625" depending on your controller
* .platform_data = &mcp251x_info,
* .irq = IRQ_EINT13,
* .max_speed_hz = 2*1000*1000,
@@ -238,6 +238,7 @@ static const struct can_bittiming_const mcp251x_bittiming_const = {
enum mcp251x_model {
CAN_MCP251X_MCP2510 = 0x2510,
CAN_MCP251X_MCP2515 = 0x2515,
+ CAN_MCP251X_MCP25625 = 0x25625,
};
struct mcp251x_priv {
@@ -280,7 +281,6 @@ static inline int mcp251x_is_##_model(struct spi_device *spi) \
}
MCP251X_IS(2510);
-MCP251X_IS(2515);
static void mcp251x_clean(struct net_device *net)
{
@@ -639,7 +639,7 @@ static int mcp251x_hw_reset(struct spi_device *spi)
/* Wait for oscillator startup timer after reset */
mdelay(MCP251X_OST_DELAY_MS);
-
+
reg = mcp251x_read_reg(spi, CANSTAT);
if ((reg & CANCTRL_REQOP_MASK) != CANCTRL_REQOP_CONF)
return -ENODEV;
@@ -820,9 +820,8 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
/* receive buffer 0 */
if (intf & CANINTF_RX0IF) {
mcp251x_hw_rx(spi, 0);
- /*
- * Free one buffer ASAP
- * (The MCP2515 does this automatically.)
+ /* Free one buffer ASAP
+ * (The MCP2515/25625 does this automatically.)
*/
if (mcp251x_is_2510(spi))
mcp251x_write_bits(spi, CANINTF, CANINTF_RX0IF, 0x00);
@@ -831,7 +830,7 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
/* receive buffer 1 */
if (intf & CANINTF_RX1IF) {
mcp251x_hw_rx(spi, 1);
- /* the MCP2515 does this automatically */
+ /* The MCP2515/25625 does this automatically. */
if (mcp251x_is_2510(spi))
clear_intf |= CANINTF_RX1IF;
}
@@ -1006,6 +1005,10 @@ static const struct of_device_id mcp251x_of_match[] = {
.compatible = "microchip,mcp2515",
.data = (void *)CAN_MCP251X_MCP2515,
},
+ {
+ .compatible = "microchip,mcp25625",
+ .data = (void *)CAN_MCP251X_MCP25625,
+ },
{ }
};
MODULE_DEVICE_TABLE(of, mcp251x_of_match);
@@ -1019,6 +1022,10 @@ static const struct spi_device_id mcp251x_id_table[] = {
.name = "mcp2515",
.driver_data = (kernel_ulong_t)CAN_MCP251X_MCP2515,
},
+ {
+ .name = "mcp25625",
+ .driver_data = (kernel_ulong_t)CAN_MCP251X_MCP25625,
+ },
{ }
};
MODULE_DEVICE_TABLE(spi, mcp251x_id_table);
@@ -1259,5 +1266,5 @@ module_spi_driver(mcp251x_can_driver);
MODULE_AUTHOR("Chris Elston <celston@katalix.com>, "
"Christian Pellegrin <chripell@evolware.org>");
-MODULE_DESCRIPTION("Microchip 251x CAN driver");
+MODULE_DESCRIPTION("Microchip 251x/25625 CAN driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 411cfb8..703e6bd 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -4816,6 +4816,8 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev)
err = PTR_ERR(chip->reset);
goto out;
}
+ if (chip->reset)
+ usleep_range(1000, 2000);
err = mv88e6xxx_detect(chip);
if (err)
diff --git a/drivers/net/dsa/mv88e6xxx/global1_vtu.c b/drivers/net/dsa/mv88e6xxx/global1_vtu.c
index 0583269..7a6667e 100644
--- a/drivers/net/dsa/mv88e6xxx/global1_vtu.c
+++ b/drivers/net/dsa/mv88e6xxx/global1_vtu.c
@@ -419,7 +419,7 @@ int mv88e6185_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip,
* VTU DBNum[7:4] are located in VTU Operation 11:8
*/
op |= entry->fid & 0x000f;
- op |= (entry->fid & 0x00f0) << 8;
+ op |= (entry->fid & 0x00f0) << 4;
}
return mv88e6xxx_g1_vtu_op(chip, op);
diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig
index f2f0264..443b34e 100644
--- a/drivers/net/ethernet/8390/Kconfig
+++ b/drivers/net/ethernet/8390/Kconfig
@@ -49,7 +49,7 @@
tristate "Amiga XSurf 100 AX88796/NE2000 clone support"
depends on ZORRO
select AX88796
- select ASIX_PHY
+ select AX88796B_PHY
help
This driver is for the Individual Computers X-Surf 100 Ethernet
card (based on the Asix AX88796 chip). If you have such a card,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index 5a727d4..33baa17 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -286,6 +286,9 @@ int bnx2x_tx_int(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata)
hw_cons = le16_to_cpu(*txdata->tx_cons_sb);
sw_cons = txdata->tx_pkt_cons;
+ /* Ensure subsequent loads occur after hw_cons */
+ smp_rmb();
+
while (sw_cons != hw_cons) {
u16 pkt_cons;
@@ -1933,8 +1936,7 @@ u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb,
}
/* select a non-FCoE queue */
- return fallback(dev, skb, NULL) %
- (BNX2X_NUM_ETH_QUEUES(bp) * bp->max_cos);
+ return fallback(dev, skb, NULL) % (BNX2X_NUM_ETH_QUEUES(bp));
}
void bnx2x_set_num_queues(struct bnx2x *bp)
@@ -3858,9 +3860,12 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
if (!(bp->flags & TX_TIMESTAMPING_EN)) {
+ bp->eth_stats.ptp_skip_tx_ts++;
BNX2X_ERR("Tx timestamping was not enabled, this packet will not be timestamped\n");
} else if (bp->ptp_tx_skb) {
- BNX2X_ERR("The device supports only a single outstanding packet to timestamp, this packet will not be timestamped\n");
+ bp->eth_stats.ptp_skip_tx_ts++;
+ netdev_err_once(bp->dev,
+ "Device supports only a single outstanding packet to timestamp, this packet won't be timestamped\n");
} else {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
/* schedule check for Tx timestamp */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
index a4a90b6c..00f9ed9 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
@@ -182,7 +182,9 @@ static const struct {
{ STATS_OFFSET32(driver_filtered_tx_pkt),
4, false, "driver_filtered_tx_pkt" },
{ STATS_OFFSET32(eee_tx_lpi),
- 4, true, "Tx LPI entry count"}
+ 4, true, "Tx LPI entry count"},
+ { STATS_OFFSET32(ptp_skip_tx_ts),
+ 4, false, "ptp_skipped_tx_tstamp" },
};
#define BNX2X_NUM_STATS ARRAY_SIZE(bnx2x_stats_arr)
@@ -1581,7 +1583,8 @@ static int bnx2x_get_module_info(struct net_device *dev,
}
if (!sff8472_comp ||
- (diag_type & SFP_EEPROM_DIAG_ADDR_CHANGE_REQ)) {
+ (diag_type & SFP_EEPROM_DIAG_ADDR_CHANGE_REQ) ||
+ !(diag_type & SFP_EEPROM_DDM_IMPLEMENTED)) {
modinfo->type = ETH_MODULE_SFF_8079;
modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
} else {
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
index b7d2511..7115f50 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
@@ -62,6 +62,7 @@
#define SFP_EEPROM_DIAG_TYPE_ADDR 0x5c
#define SFP_EEPROM_DIAG_TYPE_SIZE 1
#define SFP_EEPROM_DIAG_ADDR_CHANGE_REQ (1<<2)
+#define SFP_EEPROM_DDM_IMPLEMENTED (1<<6)
#define SFP_EEPROM_SFF_8472_COMP_ADDR 0x5e
#define SFP_EEPROM_SFF_8472_COMP_SIZE 1
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index a585f10..2c9af0f 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -15244,11 +15244,24 @@ static void bnx2x_ptp_task(struct work_struct *work)
u32 val_seq;
u64 timestamp, ns;
struct skb_shared_hwtstamps shhwtstamps;
+ bool bail = true;
+ int i;
- /* Read Tx timestamp registers */
- val_seq = REG_RD(bp, port ? NIG_REG_P1_TLLH_PTP_BUF_SEQID :
- NIG_REG_P0_TLLH_PTP_BUF_SEQID);
- if (val_seq & 0x10000) {
+ /* FW may take a while to complete timestamping; try a bit and if it's
+ * still not complete, may indicate an error state - bail out then.
+ */
+ for (i = 0; i < 10; i++) {
+ /* Read Tx timestamp registers */
+ val_seq = REG_RD(bp, port ? NIG_REG_P1_TLLH_PTP_BUF_SEQID :
+ NIG_REG_P0_TLLH_PTP_BUF_SEQID);
+ if (val_seq & 0x10000) {
+ bail = false;
+ break;
+ }
+ msleep(1 << i);
+ }
+
+ if (!bail) {
/* There is a valid timestamp value */
timestamp = REG_RD(bp, port ? NIG_REG_P1_TLLH_PTP_BUF_TS_MSB :
NIG_REG_P0_TLLH_PTP_BUF_TS_MSB);
@@ -15263,16 +15276,18 @@ static void bnx2x_ptp_task(struct work_struct *work)
memset(&shhwtstamps, 0, sizeof(shhwtstamps));
shhwtstamps.hwtstamp = ns_to_ktime(ns);
skb_tstamp_tx(bp->ptp_tx_skb, &shhwtstamps);
- dev_kfree_skb_any(bp->ptp_tx_skb);
- bp->ptp_tx_skb = NULL;
DP(BNX2X_MSG_PTP, "Tx timestamp, timestamp cycles = %llu, ns = %llu\n",
timestamp, ns);
} else {
- DP(BNX2X_MSG_PTP, "There is no valid Tx timestamp yet\n");
- /* Reschedule to keep checking for a valid timestamp value */
- schedule_work(&bp->ptp_task);
+ DP(BNX2X_MSG_PTP,
+ "Tx timestamp is not recorded (register read=%u)\n",
+ val_seq);
+ bp->eth_stats.ptp_skip_tx_ts++;
}
+
+ dev_kfree_skb_any(bp->ptp_tx_skb);
+ bp->ptp_tx_skb = NULL;
}
void bnx2x_set_rx_ts(struct bnx2x *bp, struct sk_buff *skb)
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
index b2644ed..d55e636 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
@@ -207,6 +207,9 @@ struct bnx2x_eth_stats {
u32 driver_filtered_tx_pkt;
/* src: Clear-on-Read register; Will not survive PMF Migration */
u32 eee_tx_lpi;
+
+ /* PTP */
+ u32 ptp_skip_tx_ts;
};
struct bnx2x_eth_q_stats {
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 2d6f090..fd587be 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -3086,39 +3086,42 @@ static void bcmgenet_timeout(struct net_device *dev)
netif_tx_wake_all_queues(dev);
}
-#define MAX_MC_COUNT 16
+#define MAX_MDF_FILTER 17
static inline void bcmgenet_set_mdf_addr(struct bcmgenet_priv *priv,
unsigned char *addr,
- int *i,
- int *mc)
+ int *i)
{
- u32 reg;
-
bcmgenet_umac_writel(priv, addr[0] << 8 | addr[1],
UMAC_MDF_ADDR + (*i * 4));
bcmgenet_umac_writel(priv, addr[2] << 24 | addr[3] << 16 |
addr[4] << 8 | addr[5],
UMAC_MDF_ADDR + ((*i + 1) * 4));
- reg = bcmgenet_umac_readl(priv, UMAC_MDF_CTRL);
- reg |= (1 << (MAX_MC_COUNT - *mc));
- bcmgenet_umac_writel(priv, reg, UMAC_MDF_CTRL);
*i += 2;
- (*mc)++;
}
static void bcmgenet_set_rx_mode(struct net_device *dev)
{
struct bcmgenet_priv *priv = netdev_priv(dev);
struct netdev_hw_addr *ha;
- int i, mc;
+ int i, nfilter;
u32 reg;
netif_dbg(priv, hw, dev, "%s: %08X\n", __func__, dev->flags);
- /* Promiscuous mode */
+ /* Number of filters needed */
+ nfilter = netdev_uc_count(dev) + netdev_mc_count(dev) + 2;
+
+ /*
+ * Turn on promicuous mode for three scenarios
+ * 1. IFF_PROMISC flag is set
+ * 2. IFF_ALLMULTI flag is set
+ * 3. The number of filters needed exceeds the number filters
+ * supported by the hardware.
+ */
reg = bcmgenet_umac_readl(priv, UMAC_CMD);
- if (dev->flags & IFF_PROMISC) {
+ if ((dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) ||
+ (nfilter > MAX_MDF_FILTER)) {
reg |= CMD_PROMISC;
bcmgenet_umac_writel(priv, reg, UMAC_CMD);
bcmgenet_umac_writel(priv, 0, UMAC_MDF_CTRL);
@@ -3128,32 +3131,24 @@ static void bcmgenet_set_rx_mode(struct net_device *dev)
bcmgenet_umac_writel(priv, reg, UMAC_CMD);
}
- /* UniMac doesn't support ALLMULTI */
- if (dev->flags & IFF_ALLMULTI) {
- netdev_warn(dev, "ALLMULTI is not supported\n");
- return;
- }
-
/* update MDF filter */
i = 0;
- mc = 0;
/* Broadcast */
- bcmgenet_set_mdf_addr(priv, dev->broadcast, &i, &mc);
+ bcmgenet_set_mdf_addr(priv, dev->broadcast, &i);
/* my own address.*/
- bcmgenet_set_mdf_addr(priv, dev->dev_addr, &i, &mc);
- /* Unicast list*/
- if (netdev_uc_count(dev) > (MAX_MC_COUNT - mc))
- return;
+ bcmgenet_set_mdf_addr(priv, dev->dev_addr, &i);
- if (!netdev_uc_empty(dev))
- netdev_for_each_uc_addr(ha, dev)
- bcmgenet_set_mdf_addr(priv, ha->addr, &i, &mc);
+ /* Unicast */
+ netdev_for_each_uc_addr(ha, dev)
+ bcmgenet_set_mdf_addr(priv, ha->addr, &i);
+
/* Multicast */
- if (netdev_mc_empty(dev) || netdev_mc_count(dev) >= (MAX_MC_COUNT - mc))
- return;
-
netdev_for_each_mc_addr(ha, dev)
- bcmgenet_set_mdf_addr(priv, ha->addr, &i, &mc);
+ bcmgenet_set_mdf_addr(priv, ha->addr, &i);
+
+ /* Enable filters */
+ reg = GENMASK(MAX_MDF_FILTER - 1, MAX_MDF_FILTER - nfilter);
+ bcmgenet_umac_writel(priv, reg, UMAC_MDF_CTRL);
}
/* Set the hardware MAC address. */
diff --git a/drivers/net/ethernet/cavium/liquidio/lio_core.c b/drivers/net/ethernet/cavium/liquidio/lio_core.c
index 8093c5e..7818148 100644
--- a/drivers/net/ethernet/cavium/liquidio/lio_core.c
+++ b/drivers/net/ethernet/cavium/liquidio/lio_core.c
@@ -985,7 +985,7 @@ static void liquidio_schedule_droq_pkt_handlers(struct octeon_device *oct)
if (droq->ops.poll_mode) {
droq->ops.napi_fn(droq);
- oct_priv->napi_mask |= (1 << oq_no);
+ oct_priv->napi_mask |= BIT_ULL(oq_no);
} else {
tasklet_schedule(&oct_priv->droq_tasklet);
}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
index d97e0d7..b766362 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c
@@ -1065,14 +1065,12 @@ static void cudbg_t4_fwcache(struct cudbg_init *pdbg_init,
}
}
-static int cudbg_collect_mem_region(struct cudbg_init *pdbg_init,
- struct cudbg_buffer *dbg_buff,
- struct cudbg_error *cudbg_err,
- u8 mem_type)
+static unsigned long cudbg_mem_region_size(struct cudbg_init *pdbg_init,
+ struct cudbg_error *cudbg_err,
+ u8 mem_type)
{
struct adapter *padap = pdbg_init->adap;
struct cudbg_meminfo mem_info;
- unsigned long size;
u8 mc_idx;
int rc;
@@ -1086,7 +1084,16 @@ static int cudbg_collect_mem_region(struct cudbg_init *pdbg_init,
if (rc)
return rc;
- size = mem_info.avail[mc_idx].limit - mem_info.avail[mc_idx].base;
+ return mem_info.avail[mc_idx].limit - mem_info.avail[mc_idx].base;
+}
+
+static int cudbg_collect_mem_region(struct cudbg_init *pdbg_init,
+ struct cudbg_buffer *dbg_buff,
+ struct cudbg_error *cudbg_err,
+ u8 mem_type)
+{
+ unsigned long size = cudbg_mem_region_size(pdbg_init, cudbg_err, mem_type);
+
return cudbg_read_fw_mem(pdbg_init, dbg_buff, mem_type, size,
cudbg_err);
}
diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c
index bfb16a4..d1905d5 100644
--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c
+++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c
@@ -895,7 +895,7 @@ static void be_self_test(struct net_device *netdev, struct ethtool_test *test,
u64 *data)
{
struct be_adapter *adapter = netdev_priv(netdev);
- int status;
+ int status, cnt;
u8 link_status = 0;
if (adapter->function_caps & BE_FUNCTION_CAPS_SUPER_NIC) {
@@ -906,6 +906,9 @@ static void be_self_test(struct net_device *netdev, struct ethtool_test *test,
memset(data, 0, sizeof(u64) * ETHTOOL_TESTS_NUM);
+ /* check link status before offline tests */
+ link_status = netif_carrier_ok(netdev);
+
if (test->flags & ETH_TEST_FL_OFFLINE) {
if (be_loopback_test(adapter, BE_MAC_LOOPBACK, &data[0]) != 0)
test->flags |= ETH_TEST_FL_FAILED;
@@ -926,13 +929,26 @@ static void be_self_test(struct net_device *netdev, struct ethtool_test *test,
test->flags |= ETH_TEST_FL_FAILED;
}
- status = be_cmd_link_status_query(adapter, NULL, &link_status, 0);
- if (status) {
- test->flags |= ETH_TEST_FL_FAILED;
- data[4] = -1;
- } else if (!link_status) {
+ /* link status was down prior to test */
+ if (!link_status) {
test->flags |= ETH_TEST_FL_FAILED;
data[4] = 1;
+ return;
+ }
+
+ for (cnt = 10; cnt; cnt--) {
+ status = be_cmd_link_status_query(adapter, NULL, &link_status,
+ 0);
+ if (status) {
+ test->flags |= ETH_TEST_FL_FAILED;
+ data[4] = -1;
+ break;
+ }
+
+ if (link_status)
+ break;
+
+ msleep_interruptible(500);
}
}
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index bff7475..3fe6a28 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -4700,8 +4700,12 @@ int be_update_queues(struct be_adapter *adapter)
struct net_device *netdev = adapter->netdev;
int status;
- if (netif_running(netdev))
+ if (netif_running(netdev)) {
+ /* device cannot transmit now, avoid dev_watchdog timeouts */
+ netif_carrier_off(netdev);
+
be_close(netdev);
+ }
be_cancel_worker(adapter);
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index bf715a3..4cf80de 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1689,10 +1689,10 @@ static void fec_get_mac(struct net_device *ndev)
*/
if (!is_valid_ether_addr(iap)) {
/* Report it and use a random ethernet address instead */
- netdev_err(ndev, "Invalid MAC address: %pM\n", iap);
+ dev_err(&fep->pdev->dev, "Invalid MAC address: %pM\n", iap);
eth_hw_addr_random(ndev);
- netdev_info(ndev, "Using random MAC address: %pM\n",
- ndev->dev_addr);
+ dev_info(&fep->pdev->dev, "Using random MAC address: %pM\n",
+ ndev->dev_addr);
return;
}
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.c b/drivers/net/ethernet/hisilicon/hns3/hnae3.c
index fff5be8..0594a6c 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hnae3.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.c
@@ -229,6 +229,7 @@ void hnae3_unregister_ae_algo(struct hnae3_ae_algo *ae_algo)
ae_algo->ops->uninit_ae_dev(ae_dev);
hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0);
+ ae_dev->ops = NULL;
}
list_del(&ae_algo->node);
@@ -316,6 +317,7 @@ void hnae3_unregister_ae_dev(struct hnae3_ae_dev *ae_dev)
ae_algo->ops->uninit_ae_dev(ae_dev);
hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0);
+ ae_dev->ops = NULL;
}
list_del(&ae_dev->node);
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
index 9684ad0..6a3c6b0 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
@@ -245,11 +245,13 @@ static int hns3_lp_run_test(struct net_device *ndev, enum hnae3_loop mode)
skb_get(skb);
tx_ret = hns3_nic_net_xmit(skb, ndev);
- if (tx_ret == NETDEV_TX_OK)
+ if (tx_ret == NETDEV_TX_OK) {
good_cnt++;
- else
+ } else {
+ kfree_skb(skb);
netdev_err(ndev, "hns3_lb_run_test xmit failed: %d\n",
tx_ret);
+ }
}
if (good_cnt != HNS3_NIC_LB_TEST_PKT_NUM) {
ret_val = HNS3_NIC_LB_TEST_TX_CNT_ERR;
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
index 4648c6a..89ca69f 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
@@ -663,8 +663,7 @@ static u8 *hclge_comm_get_strings(u32 stringset,
return buff;
for (i = 0; i < size; i++) {
- snprintf(buff, ETH_GSTRING_LEN,
- strs[i].desc);
+ snprintf(buff, ETH_GSTRING_LEN, "%s", strs[i].desc);
buff = buff + ETH_GSTRING_LEN;
}
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c
index 48235dc..11e9259 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c
@@ -54,7 +54,8 @@ static int hclge_shaper_para_calc(u32 ir, u8 shaper_level,
u32 tick;
/* Calc tick */
- if (shaper_level >= HCLGE_SHAPER_LVL_CNT)
+ if (shaper_level >= HCLGE_SHAPER_LVL_CNT ||
+ ir > HCLGE_ETHER_MAX_RATE)
return -EINVAL;
tick = tick_array[shaper_level];
@@ -1057,6 +1058,9 @@ static int hclge_tm_schd_mode_vnet_base_cfg(struct hclge_vport *vport)
int ret;
u8 i;
+ if (vport->vport_id >= HNAE3_MAX_TC)
+ return -EINVAL;
+
ret = hclge_tm_pri_schd_mode_cfg(hdev, vport->vport_id);
if (ret)
return ret;
diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
index 426789e..0ae43d2 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.c
+++ b/drivers/net/ethernet/ibm/ibmvnic.c
@@ -438,9 +438,10 @@ static int reset_rx_pools(struct ibmvnic_adapter *adapter)
if (rx_pool->buff_size != be64_to_cpu(size_array[i])) {
free_long_term_buff(adapter, &rx_pool->long_term_buff);
rx_pool->buff_size = be64_to_cpu(size_array[i]);
- alloc_long_term_buff(adapter, &rx_pool->long_term_buff,
- rx_pool->size *
- rx_pool->buff_size);
+ rc = alloc_long_term_buff(adapter,
+ &rx_pool->long_term_buff,
+ rx_pool->size *
+ rx_pool->buff_size);
} else {
rc = reset_long_term_buff(adapter,
&rx_pool->long_term_buff);
@@ -706,9 +707,9 @@ static int init_tx_pools(struct net_device *netdev)
return rc;
}
- init_one_tx_pool(netdev, &adapter->tso_pool[i],
- IBMVNIC_TSO_BUFS,
- IBMVNIC_TSO_BUF_SZ);
+ rc = init_one_tx_pool(netdev, &adapter->tso_pool[i],
+ IBMVNIC_TSO_BUFS,
+ IBMVNIC_TSO_BUF_SZ);
if (rc) {
release_tx_pools(adapter);
return rc;
@@ -1754,7 +1755,8 @@ static int do_reset(struct ibmvnic_adapter *adapter,
ibmvnic_cleanup(netdev);
- if (adapter->reset_reason != VNIC_RESET_MOBILITY &&
+ if (reset_state == VNIC_OPEN &&
+ adapter->reset_reason != VNIC_RESET_MOBILITY &&
adapter->reset_reason != VNIC_RESET_FAILOVER) {
rc = __ibmvnic_close(netdev);
if (rc)
@@ -1853,6 +1855,9 @@ static int do_reset(struct ibmvnic_adapter *adapter,
return 0;
}
+ /* refresh device's multicast list */
+ ibmvnic_set_multi(netdev);
+
/* kick napi */
for (i = 0; i < adapter->req_rx_queues; i++)
napi_schedule(&adapter->napi[i]);
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 8cd339c..a7b5a47 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -4208,7 +4208,7 @@ void e1000e_up(struct e1000_adapter *adapter)
e1000_configure_msix(adapter);
e1000_irq_enable(adapter);
- netif_start_queue(adapter->netdev);
+ /* Tx queue started by watchdog timer when link is up */
e1000e_trigger_lsc(adapter);
}
@@ -4584,6 +4584,7 @@ int e1000e_open(struct net_device *netdev)
pm_runtime_get_sync(&pdev->dev);
netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
/* allocate transmit descriptors */
err = e1000e_setup_tx_resources(adapter->tx_ring);
@@ -4644,7 +4645,6 @@ int e1000e_open(struct net_device *netdev)
e1000_irq_enable(adapter);
adapter->tx_hang_recheck = false;
- netif_start_queue(netdev);
hw->mac.get_link_status = true;
pm_runtime_put(&pdev->dev);
@@ -5266,6 +5266,7 @@ static void e1000_watchdog_task(struct work_struct *work)
if (phy->ops.cfg_on_link_up)
phy->ops.cfg_on_link_up(hw);
+ netif_wake_queue(netdev);
netif_carrier_on(netdev);
if (!test_bit(__E1000_DOWN, &adapter->state))
@@ -5279,6 +5280,7 @@ static void e1000_watchdog_task(struct work_struct *work)
/* Link status message must follow this format */
pr_info("%s NIC Link is Down\n", adapter->netdev->name);
netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
if (!test_bit(__E1000_DOWN, &adapter->state))
mod_timer(&adapter->phy_info_timer,
round_jiffies(jiffies + 2 * HZ));
@@ -5286,13 +5288,8 @@ static void e1000_watchdog_task(struct work_struct *work)
/* 8000ES2LAN requires a Rx packet buffer work-around
* on link down event; reset the controller to flush
* the Rx packet buffer.
- *
- * If the link is lost the controller stops DMA, but
- * if there is queued Tx work it cannot be done. So
- * reset the controller to flush the Tx packet buffers.
*/
- if ((adapter->flags & FLAG_RX_NEEDS_RESTART) ||
- e1000_desc_unused(tx_ring) + 1 < tx_ring->count)
+ if (adapter->flags & FLAG_RX_NEEDS_RESTART)
adapter->flags |= FLAG_RESTART_NOW;
else
pm_schedule_suspend(netdev->dev.parent,
@@ -5315,6 +5312,14 @@ static void e1000_watchdog_task(struct work_struct *work)
adapter->gotc_old = adapter->stats.gotc;
spin_unlock(&adapter->stats64_lock);
+ /* If the link is lost the controller stops DMA, but
+ * if there is queued Tx work it cannot be done. So
+ * reset the controller to flush the Tx packet buffers.
+ */
+ if (!netif_carrier_ok(netdev) &&
+ (e1000_desc_unused(tx_ring) + 1 < tx_ring->count))
+ adapter->flags |= FLAG_RESTART_NOW;
+
/* If reset is necessary, do it outside of interrupt context. */
if (adapter->flags & FLAG_RESTART_NOW) {
schedule_work(&adapter->reset_task);
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
index a973071..b56d22b 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
@@ -1291,7 +1291,7 @@ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring,
struct i40e_rx_buffer *rx_buffer,
unsigned int size)
{
- void *va = page_address(rx_buffer->page) + rx_buffer->page_offset;
+ void *va;
#if (PAGE_SIZE < 8192)
unsigned int truesize = i40e_rx_pg_size(rx_ring) / 2;
#else
@@ -1301,6 +1301,7 @@ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring,
struct sk_buff *skb;
/* prefetch first cache line of first page */
+ va = page_address(rx_buffer->page) + rx_buffer->page_offset;
prefetch(va);
#if L1_CACHE_BYTES < 128
prefetch(va + L1_CACHE_BYTES);
@@ -1355,7 +1356,7 @@ static struct sk_buff *i40e_build_skb(struct i40e_ring *rx_ring,
struct i40e_rx_buffer *rx_buffer,
unsigned int size)
{
- void *va = page_address(rx_buffer->page) + rx_buffer->page_offset;
+ void *va;
#if (PAGE_SIZE < 8192)
unsigned int truesize = i40e_rx_pg_size(rx_ring) / 2;
#else
@@ -1365,6 +1366,7 @@ static struct sk_buff *i40e_build_skb(struct i40e_ring *rx_ring,
struct sk_buff *skb;
/* prefetch first cache line of first page */
+ va = page_address(rx_buffer->page) + rx_buffer->page_offset;
prefetch(va);
#if L1_CACHE_BYTES < 128
prefetch(va + L1_CACHE_BYTES);
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 5aa083d..ab76a5f 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -5703,6 +5703,7 @@ static void igb_tx_ctxtdesc(struct igb_ring *tx_ring,
*/
if (tx_ring->launchtime_enable) {
ts = ns_to_timespec64(first->skb->tstamp);
+ first->skb->tstamp = 0;
context_desc->seqnum_seed = cpu_to_le32(ts.tv_nsec / 32);
} else {
context_desc->seqnum_seed = 0;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
index e5a8461..8829bd9 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
@@ -3223,7 +3223,8 @@ static int ixgbe_get_module_info(struct net_device *dev,
page_swap = true;
}
- if (sff8472_rev == IXGBE_SFF_SFF_8472_UNSUP || page_swap) {
+ if (sff8472_rev == IXGBE_SFF_SFF_8472_UNSUP || page_swap ||
+ !(addr_mode & IXGBE_SFF_DDM_IMPLEMENTED)) {
/* We have a SFP, but it does not support SFF-8472 */
modinfo->type = ETH_MODULE_SFF_8079;
modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
index 64e44e0..c56baad 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
@@ -45,6 +45,7 @@
#define IXGBE_SFF_SOFT_RS_SELECT_10G 0x8
#define IXGBE_SFF_SOFT_RS_SELECT_1G 0x0
#define IXGBE_SFF_ADDRESSING_MODE 0x4
+#define IXGBE_SFF_DDM_IMPLEMENTED 0x40
#define IXGBE_SFF_QSFP_DA_ACTIVE_CABLE 0x1
#define IXGBE_SFF_QSFP_DA_PASSIVE_CABLE 0x8
#define IXGBE_SFF_QSFP_CONNECTOR_NOT_SEPARABLE 0x23
diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c
index c5dac6b..ee78572 100644
--- a/drivers/net/ethernet/marvell/mvmdio.c
+++ b/drivers/net/ethernet/marvell/mvmdio.c
@@ -64,7 +64,7 @@
struct orion_mdio_dev {
void __iomem *regs;
- struct clk *clk[3];
+ struct clk *clk[4];
/*
* If we have access to the error interrupt pin (which is
* somewhat misnamed as it not only reflects internal errors
@@ -321,6 +321,10 @@ static int orion_mdio_probe(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(dev->clk); i++) {
dev->clk[i] = of_clk_get(pdev->dev.of_node, i);
+ if (PTR_ERR(dev->clk[i]) == -EPROBE_DEFER) {
+ ret = -EPROBE_DEFER;
+ goto out_clk;
+ }
if (IS_ERR(dev->clk[i]))
break;
clk_prepare_enable(dev->clk[i]);
@@ -362,6 +366,7 @@ static int orion_mdio_probe(struct platform_device *pdev)
if (dev->err_interrupt > 0)
writel(0, dev->regs + MVMDIO_ERR_INT_MASK);
+out_clk:
for (i = 0; i < ARRAY_SIZE(dev->clk); i++) {
if (IS_ERR(dev->clk[i]))
break;
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
index df5b74f..6455511 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
@@ -3501,6 +3501,7 @@ static int mvpp2_set_mac_address(struct net_device *dev, void *p)
static int mvpp2_change_mtu(struct net_device *dev, int mtu)
{
struct mvpp2_port *port = netdev_priv(dev);
+ bool running = netif_running(dev);
int err;
if (!IS_ALIGNED(MVPP2_RX_PKT_SIZE(mtu), 8)) {
@@ -3509,40 +3510,24 @@ static int mvpp2_change_mtu(struct net_device *dev, int mtu)
mtu = ALIGN(MVPP2_RX_PKT_SIZE(mtu), 8);
}
- if (!netif_running(dev)) {
- err = mvpp2_bm_update_mtu(dev, mtu);
- if (!err) {
- port->pkt_size = MVPP2_RX_PKT_SIZE(mtu);
- return 0;
- }
-
- /* Reconfigure BM to the original MTU */
- err = mvpp2_bm_update_mtu(dev, dev->mtu);
- if (err)
- goto log_error;
- }
-
- mvpp2_stop_dev(port);
+ if (running)
+ mvpp2_stop_dev(port);
err = mvpp2_bm_update_mtu(dev, mtu);
- if (!err) {
+ if (err) {
+ netdev_err(dev, "failed to change MTU\n");
+ /* Reconfigure BM to the original MTU */
+ mvpp2_bm_update_mtu(dev, dev->mtu);
+ } else {
port->pkt_size = MVPP2_RX_PKT_SIZE(mtu);
- goto out_start;
}
- /* Reconfigure BM to the original MTU */
- err = mvpp2_bm_update_mtu(dev, dev->mtu);
- if (err)
- goto log_error;
+ if (running) {
+ mvpp2_start_dev(port);
+ mvpp2_egress_enable(port);
+ mvpp2_ingress_enable(port);
+ }
-out_start:
- mvpp2_start_dev(port);
- mvpp2_egress_enable(port);
- mvpp2_ingress_enable(port);
-
- return 0;
-log_error:
- netdev_err(dev, "failed to change MTU\n");
return err;
}
@@ -5358,9 +5343,6 @@ static int mvpp2_remove(struct platform_device *pdev)
mvpp2_dbgfs_cleanup(priv);
- flush_workqueue(priv->stats_queue);
- destroy_workqueue(priv->stats_queue);
-
fwnode_for_each_available_child_node(fwnode, port_fwnode) {
if (priv->port_list[i]) {
mutex_destroy(&priv->port_list[i]->gather_stats_lock);
@@ -5369,6 +5351,8 @@ static int mvpp2_remove(struct platform_device *pdev)
i++;
}
+ destroy_workqueue(priv->stats_queue);
+
for (i = 0; i < MVPP2_BM_POOLS_NUM; i++) {
struct mvpp2_bm_pool *bm_pool = &priv->bm_pools[i];
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c
index ae22400..5692c60 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c
@@ -312,7 +312,8 @@ static void mvpp2_prs_sram_shift_set(struct mvpp2_prs_entry *pe, int shift,
}
/* Set value */
- pe->sram[MVPP2_BIT_TO_WORD(MVPP2_PRS_SRAM_SHIFT_OFFS)] = shift & MVPP2_PRS_SRAM_SHIFT_MASK;
+ pe->sram[MVPP2_BIT_TO_WORD(MVPP2_PRS_SRAM_SHIFT_OFFS)] |=
+ shift & MVPP2_PRS_SRAM_SHIFT_MASK;
/* Reset and set operation */
mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_SHIFT_OFFS,
diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c
index 1485f66..4ade864 100644
--- a/drivers/net/ethernet/marvell/sky2.c
+++ b/drivers/net/ethernet/marvell/sky2.c
@@ -4947,6 +4947,13 @@ static const struct dmi_system_id msi_blacklist[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "P-79"),
},
},
+ {
+ .ident = "ASUS P6T",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "P6T"),
+ },
+ },
{}
};
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dev.c b/drivers/net/ethernet/mellanox/mlx5/core/dev.c
index 1c225be..3692d6a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/dev.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/dev.c
@@ -307,7 +307,7 @@ void mlx5_unregister_device(struct mlx5_core_dev *dev)
struct mlx5_interface *intf;
mutex_lock(&mlx5_intf_mutex);
- list_for_each_entry(intf, &intf_list, list)
+ list_for_each_entry_reverse(intf, &intf_list, list)
mlx5_remove_device(intf, priv);
list_del(&priv->dev_list);
mutex_unlock(&mlx5_intf_mutex);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 0f1c296..83ab2c0 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -420,12 +420,11 @@ static inline u64 mlx5e_get_mpwqe_offset(struct mlx5e_rq *rq, u16 wqe_ix)
static void mlx5e_init_frags_partition(struct mlx5e_rq *rq)
{
- struct mlx5e_wqe_frag_info next_frag, *prev;
+ struct mlx5e_wqe_frag_info next_frag = {};
+ struct mlx5e_wqe_frag_info *prev = NULL;
int i;
next_frag.di = &rq->wqe.di[0];
- next_frag.offset = 0;
- prev = NULL;
for (i = 0; i < mlx5_wq_cyc_get_size(&rq->wqe.wq); i++) {
struct mlx5e_rq_frag_info *frag_info = &rq->wqe.info.arr[0];
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index 9f7f842..c8928ce 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -992,13 +992,13 @@ void mlx5e_tc_encap_flows_del(struct mlx5e_priv *priv,
void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe)
{
struct mlx5e_neigh *m_neigh = &nhe->m_neigh;
- u64 bytes, packets, lastuse = 0;
struct mlx5e_tc_flow *flow;
struct mlx5e_encap_entry *e;
struct mlx5_fc *counter;
struct neigh_table *tbl;
bool neigh_used = false;
struct neighbour *n;
+ u64 lastuse;
if (m_neigh->family == AF_INET)
tbl = &arp_tbl;
@@ -1015,7 +1015,7 @@ void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe)
list_for_each_entry(flow, &e->flows, encap) {
if (flow->flags & MLX5E_TC_FLOW_OFFLOADED) {
counter = mlx5_flow_rule_counter(flow->rule[0]);
- mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse);
+ lastuse = mlx5_fc_query_lastuse(counter);
if (time_after((unsigned long)lastuse, nhe->reported_lastuse)) {
neigh_used = true;
break;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
index 58af6be..808ddd7 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
@@ -321,6 +321,11 @@ int mlx5_fc_query(struct mlx5_core_dev *dev, struct mlx5_fc *counter,
}
EXPORT_SYMBOL(mlx5_fc_query);
+u64 mlx5_fc_query_lastuse(struct mlx5_fc *counter)
+{
+ return counter->cache.lastuse;
+}
+
void mlx5_fc_query_cached(struct mlx5_fc *counter,
u64 *bytes, u64 *packets, u64 *lastuse)
{
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
index 5b7fe82..db6aafc 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
@@ -662,7 +662,9 @@ struct net_device *mlx5_rdma_netdev_alloc(struct mlx5_core_dev *mdev,
profile->init(mdev, netdev, profile, ipriv);
- mlx5e_attach_netdev(epriv);
+ err = mlx5e_attach_netdev(epriv);
+ if (err)
+ goto detach;
netif_carrier_off(netdev);
/* set rdma_netdev func pointers */
@@ -678,6 +680,11 @@ struct net_device *mlx5_rdma_netdev_alloc(struct mlx5_core_dev *mdev,
return netdev;
+detach:
+ profile->cleanup(epriv);
+ if (ipriv->sub_interface)
+ return NULL;
+ mlx5e_destroy_mdev_resources(mdev);
destroy_ht:
mlx5i_pkey_qpn_ht_cleanup(netdev);
destroy_wq:
diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h
index 6e8b619..aee58b3 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h
@@ -877,7 +877,7 @@ static inline void mlxsw_reg_spaft_pack(char *payload, u8 local_port,
MLXSW_REG_ZERO(spaft, payload);
mlxsw_reg_spaft_local_port_set(payload, local_port);
mlxsw_reg_spaft_allow_untagged_set(payload, allow_untagged);
- mlxsw_reg_spaft_allow_prio_tagged_set(payload, true);
+ mlxsw_reg_spaft_allow_prio_tagged_set(payload, allow_untagged);
mlxsw_reg_spaft_allow_tagged_set(payload, true);
}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index 0cab060..ee126bc 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -5032,7 +5032,7 @@ static int __init mlxsw_sp_module_init(void)
return 0;
err_sp2_pci_driver_register:
- mlxsw_pci_driver_unregister(&mlxsw_sp2_pci_driver);
+ mlxsw_pci_driver_unregister(&mlxsw_sp1_pci_driver);
err_sp1_pci_driver_register:
mlxsw_core_driver_unregister(&mlxsw_sp2_driver);
err_sp2_core_driver_register:
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_dcb.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_dcb.c
index b25048c..21296fa 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_dcb.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_dcb.c
@@ -408,14 +408,6 @@ static int mlxsw_sp_port_dcb_app_update(struct mlxsw_sp_port *mlxsw_sp_port)
have_dscp = mlxsw_sp_port_dcb_app_prio_dscp_map(mlxsw_sp_port,
&prio_map);
- if (!have_dscp) {
- err = mlxsw_sp_port_dcb_toggle_trust(mlxsw_sp_port,
- MLXSW_REG_QPTS_TRUST_STATE_PCP);
- if (err)
- netdev_err(mlxsw_sp_port->dev, "Couldn't switch to trust L2\n");
- return err;
- }
-
mlxsw_sp_port_dcb_app_dscp_prio_map(mlxsw_sp_port, default_prio,
&dscp_map);
err = mlxsw_sp_port_dcb_app_update_qpdpm(mlxsw_sp_port,
@@ -432,6 +424,14 @@ static int mlxsw_sp_port_dcb_app_update(struct mlxsw_sp_port *mlxsw_sp_port)
return err;
}
+ if (!have_dscp) {
+ err = mlxsw_sp_port_dcb_toggle_trust(mlxsw_sp_port,
+ MLXSW_REG_QPTS_TRUST_STATE_PCP);
+ if (err)
+ netdev_err(mlxsw_sp_port->dev, "Couldn't switch to trust L2\n");
+ return err;
+ }
+
err = mlxsw_sp_port_dcb_toggle_trust(mlxsw_sp_port,
MLXSW_REG_QPTS_TRUST_STATE_DSCP);
if (err) {
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
index 1029119..732ba21 100644
--- a/drivers/net/ethernet/mscc/ocelot.c
+++ b/drivers/net/ethernet/mscc/ocelot.c
@@ -1767,6 +1767,7 @@ EXPORT_SYMBOL(ocelot_init);
void ocelot_deinit(struct ocelot *ocelot)
{
+ cancel_delayed_work(&ocelot->stats_work);
destroy_workqueue(ocelot->stats_queue);
mutex_destroy(&ocelot->stats_lock);
}
diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c
index 4dd82a1..a6a9688 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_dev.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c
@@ -3096,6 +3096,7 @@ static void qed_nvm_info_free(struct qed_hwfn *p_hwfn)
static int qed_hw_prepare_single(struct qed_hwfn *p_hwfn,
void __iomem *p_regview,
void __iomem *p_doorbells,
+ u64 db_phys_addr,
enum qed_pci_personality personality)
{
int rc = 0;
@@ -3103,6 +3104,7 @@ static int qed_hw_prepare_single(struct qed_hwfn *p_hwfn,
/* Split PCI bars evenly between hwfns */
p_hwfn->regview = p_regview;
p_hwfn->doorbells = p_doorbells;
+ p_hwfn->db_phys_addr = db_phys_addr;
if (IS_VF(p_hwfn->cdev))
return qed_vf_hw_prepare(p_hwfn);
@@ -3198,7 +3200,9 @@ int qed_hw_prepare(struct qed_dev *cdev,
/* Initialize the first hwfn - will learn number of hwfns */
rc = qed_hw_prepare_single(p_hwfn,
cdev->regview,
- cdev->doorbells, personality);
+ cdev->doorbells,
+ cdev->db_phys_addr,
+ personality);
if (rc)
return rc;
@@ -3207,22 +3211,25 @@ int qed_hw_prepare(struct qed_dev *cdev,
/* Initialize the rest of the hwfns */
if (cdev->num_hwfns > 1) {
void __iomem *p_regview, *p_doorbell;
- u8 __iomem *addr;
+ u64 db_phys_addr;
+ u32 offset;
/* adjust bar offset for second engine */
- addr = cdev->regview +
- qed_hw_bar_size(p_hwfn, p_hwfn->p_main_ptt,
- BAR_ID_0) / 2;
- p_regview = addr;
+ offset = qed_hw_bar_size(p_hwfn, p_hwfn->p_main_ptt,
+ BAR_ID_0) / 2;
+ p_regview = cdev->regview + offset;
- addr = cdev->doorbells +
- qed_hw_bar_size(p_hwfn, p_hwfn->p_main_ptt,
- BAR_ID_1) / 2;
- p_doorbell = addr;
+ offset = qed_hw_bar_size(p_hwfn, p_hwfn->p_main_ptt,
+ BAR_ID_1) / 2;
+
+ p_doorbell = cdev->doorbells + offset;
+
+ db_phys_addr = cdev->db_phys_addr + offset;
/* prepare second hw function */
rc = qed_hw_prepare_single(&cdev->hwfns[1], p_regview,
- p_doorbell, personality);
+ p_doorbell, db_phys_addr,
+ personality);
/* in case of error, need to free the previously
* initiliazed hwfn 0.
diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index b7471e4..7002a66 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -2709,6 +2709,8 @@ qed_iwarp_ll2_start(struct qed_hwfn *p_hwfn,
data.input.rx_num_desc = n_ooo_bufs * 2;
data.input.tx_num_desc = data.input.rx_num_desc;
data.input.tx_max_bds_per_packet = QED_IWARP_MAX_BDS_PER_FPDU;
+ data.input.tx_tc = PKT_LB_TC;
+ data.input.tx_dest = QED_LL2_TX_DEST_LB;
data.p_connection_handle = &iwarp_info->ll2_mpa_handle;
data.input.secondary_queue = true;
data.cbs = &cbs;
diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.c b/drivers/net/ethernet/qlogic/qed/qed_rdma.c
index 7873d6df..13802b8 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_rdma.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.c
@@ -803,7 +803,7 @@ static int qed_rdma_add_user(void *rdma_cxt,
dpi_start_offset +
((out_params->dpi) * p_hwfn->dpi_size));
- out_params->dpi_phys_addr = p_hwfn->cdev->db_phys_addr +
+ out_params->dpi_phys_addr = p_hwfn->db_phys_addr +
dpi_start_offset +
((out_params->dpi) * p_hwfn->dpi_size);
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
index aaad5e4..e6ce895 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
@@ -389,14 +389,13 @@ static int rmnet_changelink(struct net_device *dev, struct nlattr *tb[],
}
if (data[IFLA_RMNET_UL_AGG_PARAMS]) {
- void *agg_params;
- unsigned long irq_flags;
+ struct rmnet_egress_agg_params *agg_params;
agg_params = nla_data(data[IFLA_RMNET_UL_AGG_PARAMS]);
- spin_lock_irqsave(&port->agg_lock, irq_flags);
- memcpy(&port->egress_agg_params, agg_params,
- sizeof(port->egress_agg_params));
- spin_unlock_irqrestore(&port->agg_lock, irq_flags);
+ rmnet_map_update_ul_agg_config(port, agg_params->agg_size,
+ agg_params->agg_count,
+ agg_params->agg_features,
+ agg_params->agg_time);
}
return 0;
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
index 07b1154..2359401 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
@@ -20,6 +20,11 @@ struct rmnet_endpoint {
struct hlist_node hlnode;
};
+struct rmnet_agg_stats {
+ u64 ul_agg_reuse;
+ u64 ul_agg_alloc;
+};
+
struct rmnet_port_priv_stats {
u64 dl_hdr_last_qmap_vers;
u64 dl_hdr_last_ep_id;
@@ -33,14 +38,21 @@ struct rmnet_port_priv_stats {
u64 dl_hdr_total_pkts;
u64 dl_trl_last_seq;
u64 dl_trl_count;
+ struct rmnet_agg_stats agg;
};
struct rmnet_egress_agg_params {
u16 agg_size;
- u16 agg_count;
+ u8 agg_count;
+ u8 agg_features;
u32 agg_time;
};
+struct rmnet_agg_page {
+ struct list_head list;
+ struct page *page;
+};
+
/* One instance of this structure is instantiated for each real_dev associated
* with rmnet.
*/
@@ -65,6 +77,9 @@ struct rmnet_port {
struct timespec agg_last;
struct hrtimer hrtimer;
struct work_struct agg_wq;
+ u8 agg_size_order;
+ struct list_head agg_list;
+ struct rmnet_agg_page *agg_head;
void *qmi_info;
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h
index f575096..04048f6 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h
@@ -261,6 +261,8 @@ int rmnet_map_tx_agg_skip(struct sk_buff *skb, int offset);
void rmnet_map_tx_aggregate(struct sk_buff *skb, struct rmnet_port *port);
void rmnet_map_tx_aggregate_init(struct rmnet_port *port);
void rmnet_map_tx_aggregate_exit(struct rmnet_port *port);
+void rmnet_map_update_ul_agg_config(struct rmnet_port *port, u16 size,
+ u8 count, u8 features, u32 time);
void rmnet_map_dl_hdr_notify(struct rmnet_port *port,
struct rmnet_map_dl_ind_hdr *dl_hdr);
void rmnet_map_dl_hdr_notify_v2(struct rmnet_port *port,
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
index fcb1d2d..29f45d2 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c
@@ -1250,6 +1250,113 @@ static void rmnet_map_linearize_copy(struct sk_buff *dst, struct sk_buff *src)
}
}
+static void rmnet_free_agg_pages(struct rmnet_port *port)
+{
+ struct rmnet_agg_page *agg_page, *idx;
+
+ list_for_each_entry_safe(agg_page, idx, &port->agg_list, list) {
+ put_page(agg_page->page);
+ kfree(agg_page);
+ }
+
+ port->agg_head = NULL;
+}
+
+static struct page *rmnet_get_agg_pages(struct rmnet_port *port)
+{
+ struct rmnet_agg_page *agg_page;
+ struct page *page = NULL;
+ int i = 0;
+
+ if (!(port->egress_agg_params.agg_features & RMNET_PAGE_RECYCLE))
+ goto alloc;
+
+ do {
+ agg_page = port->agg_head;
+ if (unlikely(!agg_page))
+ break;
+
+ if (page_ref_count(agg_page->page) == 1) {
+ page = agg_page->page;
+ page_ref_inc(agg_page->page);
+
+ port->stats.agg.ul_agg_reuse++;
+ port->agg_head = list_next_entry(agg_page, list);
+ break;
+ }
+
+ port->agg_head = list_next_entry(agg_page, list);
+ i++;
+ } while (i <= 5);
+
+alloc:
+ if (!page) {
+ page = __dev_alloc_pages(GFP_ATOMIC, port->agg_size_order);
+ port->stats.agg.ul_agg_alloc++;
+ }
+
+ return page;
+}
+
+static struct rmnet_agg_page *__rmnet_alloc_agg_pages(struct rmnet_port *port)
+{
+ struct rmnet_agg_page *agg_page;
+ struct page *page;
+
+ agg_page = kzalloc(sizeof(*agg_page), GFP_ATOMIC);
+ if (!agg_page)
+ return NULL;
+
+ page = __dev_alloc_pages(GFP_ATOMIC, port->agg_size_order);
+ if (!page) {
+ kfree(agg_page);
+ return NULL;
+ }
+
+ agg_page->page = page;
+
+ return agg_page;
+}
+
+static void rmnet_alloc_agg_pages(struct rmnet_port *port)
+{
+ struct rmnet_agg_page *agg_page = NULL;
+ int i = 0;
+
+ for (i = 0; i < 512; i++) {
+ agg_page = __rmnet_alloc_agg_pages(port);
+
+ if (agg_page)
+ list_add_tail(&agg_page->list, &port->agg_list);
+ }
+
+ port->agg_head = list_first_entry_or_null(&port->agg_list,
+ struct rmnet_agg_page, list);
+}
+
+static struct sk_buff *rmnet_map_build_skb(struct rmnet_port *port)
+{
+ struct sk_buff *skb;
+ unsigned int size;
+ struct page *page;
+ void *vaddr;
+
+ page = rmnet_get_agg_pages(port);
+ if (!page)
+ return NULL;
+
+ vaddr = page_address(page);
+ size = PAGE_SIZE << port->agg_size_order;
+
+ skb = build_skb(vaddr, size);
+ if (!skb) {
+ put_page(page);
+ return NULL;
+ }
+
+ return skb;
+}
+
void rmnet_map_tx_aggregate(struct sk_buff *skb, struct rmnet_port *port)
{
struct timespec diff, last;
@@ -1277,8 +1384,7 @@ void rmnet_map_tx_aggregate(struct sk_buff *skb, struct rmnet_port *port)
return;
}
- port->agg_skb = alloc_skb(port->egress_agg_params.agg_size,
- GFP_ATOMIC);
+ port->agg_skb = rmnet_map_build_skb(port);
if (!port->agg_skb) {
port->agg_skb = 0;
port->agg_count = 0;
@@ -1328,14 +1434,51 @@ void rmnet_map_tx_aggregate(struct sk_buff *skb, struct rmnet_port *port)
spin_unlock_irqrestore(&port->agg_lock, flags);
}
+void rmnet_map_update_ul_agg_config(struct rmnet_port *port, u16 size,
+ u8 count, u8 features, u32 time)
+{
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&port->agg_lock, irq_flags);
+ port->egress_agg_params.agg_count = count;
+ port->egress_agg_params.agg_time = time;
+ port->egress_agg_params.agg_size = size;
+ port->egress_agg_params.agg_features = features;
+
+ rmnet_free_agg_pages(port);
+
+ /* This effectively disables recycling in case the UL aggregation
+ * size is lesser than PAGE_SIZE.
+ */
+ if (size < PAGE_SIZE)
+ goto done;
+
+ port->agg_size_order = get_order(size);
+
+ size = PAGE_SIZE << port->agg_size_order;
+ size -= SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+ port->egress_agg_params.agg_size = size;
+
+ if (port->egress_agg_params.agg_features == RMNET_PAGE_RECYCLE)
+ rmnet_alloc_agg_pages(port);
+
+done:
+ spin_unlock_irqrestore(&port->agg_lock, irq_flags);
+}
+
void rmnet_map_tx_aggregate_init(struct rmnet_port *port)
{
hrtimer_init(&port->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
port->hrtimer.function = rmnet_map_flush_tx_packet_queue;
- port->egress_agg_params.agg_size = 8192;
- port->egress_agg_params.agg_count = 20;
- port->egress_agg_params.agg_time = 3000000;
spin_lock_init(&port->agg_lock);
+ INIT_LIST_HEAD(&port->agg_list);
+
+ /* Since PAGE_SIZE - 1 is specified here, no pages are pre-allocated.
+ * This is done to reduce memory usage in cases where
+ * UL aggregation is disabled.
+ * Additionally, the features flag is also set to 0.
+ */
+ rmnet_map_update_ul_agg_config(port, PAGE_SIZE - 1, 20, 0, 3000000);
INIT_WORK(&port->agg_wq, rmnet_map_flush_tx_packet_work);
}
@@ -1359,6 +1502,7 @@ void rmnet_map_tx_aggregate_exit(struct rmnet_port *port)
port->agg_state = 0;
}
+ rmnet_free_agg_pages(port);
spin_unlock_irqrestore(&port->agg_lock, flags);
}
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h
index e5c530c..2ce29bf 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_private.h
@@ -22,6 +22,9 @@ RMNET_INGRESS_FORMAT_DL_MARKER_V2)
#define RMNET_INGRESS_FORMAT_PS BIT(27)
#define RMNET_FORMAT_PS_NOTIF BIT(26)
+/* UL Aggregation parameters */
+#define RMNET_PAGE_RECYCLE BIT(0)
+
/* Replace skb->dev to a virtual rmnet device and pass up the stack */
#define RMNET_EPMODE_VND (1)
/* Pass the frame directly to another device with dev_queue_xmit() */
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
index 1edf9e7..f00f1ce 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
@@ -226,6 +226,8 @@ static const char rmnet_port_gstrings_stats[][ETH_GSTRING_LEN] = {
"DL header total pkts received",
"DL trailer last seen sequence",
"DL trailer pkts received",
+ "UL agg reuse",
+ "UL agg alloc",
};
static void rmnet_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
@@ -276,6 +278,7 @@ static int rmnet_stats_reset(struct net_device *dev)
{
struct rmnet_priv *priv = netdev_priv(dev);
struct rmnet_port_priv_stats *stp;
+ struct rmnet_priv_stats *st;
struct rmnet_port *port;
port = rmnet_get_port(priv->real_dev);
@@ -285,6 +288,11 @@ static int rmnet_stats_reset(struct net_device *dev)
stp = &port->stats;
memset(stp, 0, sizeof(*stp));
+
+ st = &priv->stats;
+
+ memset(st, 0, sizeof(*st));
+
return 0;
}
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 7a50b91..0c8b714 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -5202,6 +5202,143 @@ static void rtl_hw_start_8411_2(struct rtl8169_private *tp)
/* disable aspm and clock request before access ephy */
rtl_hw_aspm_clkreq_enable(tp, false);
rtl_ephy_init(tp, e_info_8411_2, ARRAY_SIZE(e_info_8411_2));
+
+ /* The following Realtek-provided magic fixes an issue with the RX unit
+ * getting confused after the PHY having been powered-down.
+ */
+ r8168_mac_ocp_write(tp, 0xFC28, 0x0000);
+ r8168_mac_ocp_write(tp, 0xFC2A, 0x0000);
+ r8168_mac_ocp_write(tp, 0xFC2C, 0x0000);
+ r8168_mac_ocp_write(tp, 0xFC2E, 0x0000);
+ r8168_mac_ocp_write(tp, 0xFC30, 0x0000);
+ r8168_mac_ocp_write(tp, 0xFC32, 0x0000);
+ r8168_mac_ocp_write(tp, 0xFC34, 0x0000);
+ r8168_mac_ocp_write(tp, 0xFC36, 0x0000);
+ mdelay(3);
+ r8168_mac_ocp_write(tp, 0xFC26, 0x0000);
+
+ r8168_mac_ocp_write(tp, 0xF800, 0xE008);
+ r8168_mac_ocp_write(tp, 0xF802, 0xE00A);
+ r8168_mac_ocp_write(tp, 0xF804, 0xE00C);
+ r8168_mac_ocp_write(tp, 0xF806, 0xE00E);
+ r8168_mac_ocp_write(tp, 0xF808, 0xE027);
+ r8168_mac_ocp_write(tp, 0xF80A, 0xE04F);
+ r8168_mac_ocp_write(tp, 0xF80C, 0xE05E);
+ r8168_mac_ocp_write(tp, 0xF80E, 0xE065);
+ r8168_mac_ocp_write(tp, 0xF810, 0xC602);
+ r8168_mac_ocp_write(tp, 0xF812, 0xBE00);
+ r8168_mac_ocp_write(tp, 0xF814, 0x0000);
+ r8168_mac_ocp_write(tp, 0xF816, 0xC502);
+ r8168_mac_ocp_write(tp, 0xF818, 0xBD00);
+ r8168_mac_ocp_write(tp, 0xF81A, 0x074C);
+ r8168_mac_ocp_write(tp, 0xF81C, 0xC302);
+ r8168_mac_ocp_write(tp, 0xF81E, 0xBB00);
+ r8168_mac_ocp_write(tp, 0xF820, 0x080A);
+ r8168_mac_ocp_write(tp, 0xF822, 0x6420);
+ r8168_mac_ocp_write(tp, 0xF824, 0x48C2);
+ r8168_mac_ocp_write(tp, 0xF826, 0x8C20);
+ r8168_mac_ocp_write(tp, 0xF828, 0xC516);
+ r8168_mac_ocp_write(tp, 0xF82A, 0x64A4);
+ r8168_mac_ocp_write(tp, 0xF82C, 0x49C0);
+ r8168_mac_ocp_write(tp, 0xF82E, 0xF009);
+ r8168_mac_ocp_write(tp, 0xF830, 0x74A2);
+ r8168_mac_ocp_write(tp, 0xF832, 0x8CA5);
+ r8168_mac_ocp_write(tp, 0xF834, 0x74A0);
+ r8168_mac_ocp_write(tp, 0xF836, 0xC50E);
+ r8168_mac_ocp_write(tp, 0xF838, 0x9CA2);
+ r8168_mac_ocp_write(tp, 0xF83A, 0x1C11);
+ r8168_mac_ocp_write(tp, 0xF83C, 0x9CA0);
+ r8168_mac_ocp_write(tp, 0xF83E, 0xE006);
+ r8168_mac_ocp_write(tp, 0xF840, 0x74F8);
+ r8168_mac_ocp_write(tp, 0xF842, 0x48C4);
+ r8168_mac_ocp_write(tp, 0xF844, 0x8CF8);
+ r8168_mac_ocp_write(tp, 0xF846, 0xC404);
+ r8168_mac_ocp_write(tp, 0xF848, 0xBC00);
+ r8168_mac_ocp_write(tp, 0xF84A, 0xC403);
+ r8168_mac_ocp_write(tp, 0xF84C, 0xBC00);
+ r8168_mac_ocp_write(tp, 0xF84E, 0x0BF2);
+ r8168_mac_ocp_write(tp, 0xF850, 0x0C0A);
+ r8168_mac_ocp_write(tp, 0xF852, 0xE434);
+ r8168_mac_ocp_write(tp, 0xF854, 0xD3C0);
+ r8168_mac_ocp_write(tp, 0xF856, 0x49D9);
+ r8168_mac_ocp_write(tp, 0xF858, 0xF01F);
+ r8168_mac_ocp_write(tp, 0xF85A, 0xC526);
+ r8168_mac_ocp_write(tp, 0xF85C, 0x64A5);
+ r8168_mac_ocp_write(tp, 0xF85E, 0x1400);
+ r8168_mac_ocp_write(tp, 0xF860, 0xF007);
+ r8168_mac_ocp_write(tp, 0xF862, 0x0C01);
+ r8168_mac_ocp_write(tp, 0xF864, 0x8CA5);
+ r8168_mac_ocp_write(tp, 0xF866, 0x1C15);
+ r8168_mac_ocp_write(tp, 0xF868, 0xC51B);
+ r8168_mac_ocp_write(tp, 0xF86A, 0x9CA0);
+ r8168_mac_ocp_write(tp, 0xF86C, 0xE013);
+ r8168_mac_ocp_write(tp, 0xF86E, 0xC519);
+ r8168_mac_ocp_write(tp, 0xF870, 0x74A0);
+ r8168_mac_ocp_write(tp, 0xF872, 0x48C4);
+ r8168_mac_ocp_write(tp, 0xF874, 0x8CA0);
+ r8168_mac_ocp_write(tp, 0xF876, 0xC516);
+ r8168_mac_ocp_write(tp, 0xF878, 0x74A4);
+ r8168_mac_ocp_write(tp, 0xF87A, 0x48C8);
+ r8168_mac_ocp_write(tp, 0xF87C, 0x48CA);
+ r8168_mac_ocp_write(tp, 0xF87E, 0x9CA4);
+ r8168_mac_ocp_write(tp, 0xF880, 0xC512);
+ r8168_mac_ocp_write(tp, 0xF882, 0x1B00);
+ r8168_mac_ocp_write(tp, 0xF884, 0x9BA0);
+ r8168_mac_ocp_write(tp, 0xF886, 0x1B1C);
+ r8168_mac_ocp_write(tp, 0xF888, 0x483F);
+ r8168_mac_ocp_write(tp, 0xF88A, 0x9BA2);
+ r8168_mac_ocp_write(tp, 0xF88C, 0x1B04);
+ r8168_mac_ocp_write(tp, 0xF88E, 0xC508);
+ r8168_mac_ocp_write(tp, 0xF890, 0x9BA0);
+ r8168_mac_ocp_write(tp, 0xF892, 0xC505);
+ r8168_mac_ocp_write(tp, 0xF894, 0xBD00);
+ r8168_mac_ocp_write(tp, 0xF896, 0xC502);
+ r8168_mac_ocp_write(tp, 0xF898, 0xBD00);
+ r8168_mac_ocp_write(tp, 0xF89A, 0x0300);
+ r8168_mac_ocp_write(tp, 0xF89C, 0x051E);
+ r8168_mac_ocp_write(tp, 0xF89E, 0xE434);
+ r8168_mac_ocp_write(tp, 0xF8A0, 0xE018);
+ r8168_mac_ocp_write(tp, 0xF8A2, 0xE092);
+ r8168_mac_ocp_write(tp, 0xF8A4, 0xDE20);
+ r8168_mac_ocp_write(tp, 0xF8A6, 0xD3C0);
+ r8168_mac_ocp_write(tp, 0xF8A8, 0xC50F);
+ r8168_mac_ocp_write(tp, 0xF8AA, 0x76A4);
+ r8168_mac_ocp_write(tp, 0xF8AC, 0x49E3);
+ r8168_mac_ocp_write(tp, 0xF8AE, 0xF007);
+ r8168_mac_ocp_write(tp, 0xF8B0, 0x49C0);
+ r8168_mac_ocp_write(tp, 0xF8B2, 0xF103);
+ r8168_mac_ocp_write(tp, 0xF8B4, 0xC607);
+ r8168_mac_ocp_write(tp, 0xF8B6, 0xBE00);
+ r8168_mac_ocp_write(tp, 0xF8B8, 0xC606);
+ r8168_mac_ocp_write(tp, 0xF8BA, 0xBE00);
+ r8168_mac_ocp_write(tp, 0xF8BC, 0xC602);
+ r8168_mac_ocp_write(tp, 0xF8BE, 0xBE00);
+ r8168_mac_ocp_write(tp, 0xF8C0, 0x0C4C);
+ r8168_mac_ocp_write(tp, 0xF8C2, 0x0C28);
+ r8168_mac_ocp_write(tp, 0xF8C4, 0x0C2C);
+ r8168_mac_ocp_write(tp, 0xF8C6, 0xDC00);
+ r8168_mac_ocp_write(tp, 0xF8C8, 0xC707);
+ r8168_mac_ocp_write(tp, 0xF8CA, 0x1D00);
+ r8168_mac_ocp_write(tp, 0xF8CC, 0x8DE2);
+ r8168_mac_ocp_write(tp, 0xF8CE, 0x48C1);
+ r8168_mac_ocp_write(tp, 0xF8D0, 0xC502);
+ r8168_mac_ocp_write(tp, 0xF8D2, 0xBD00);
+ r8168_mac_ocp_write(tp, 0xF8D4, 0x00AA);
+ r8168_mac_ocp_write(tp, 0xF8D6, 0xE0C0);
+ r8168_mac_ocp_write(tp, 0xF8D8, 0xC502);
+ r8168_mac_ocp_write(tp, 0xF8DA, 0xBD00);
+ r8168_mac_ocp_write(tp, 0xF8DC, 0x0132);
+
+ r8168_mac_ocp_write(tp, 0xFC26, 0x8000);
+
+ r8168_mac_ocp_write(tp, 0xFC2A, 0x0743);
+ r8168_mac_ocp_write(tp, 0xFC2C, 0x0801);
+ r8168_mac_ocp_write(tp, 0xFC2E, 0x0BE9);
+ r8168_mac_ocp_write(tp, 0xFC30, 0x02FD);
+ r8168_mac_ocp_write(tp, 0xFC32, 0x0C25);
+ r8168_mac_ocp_write(tp, 0xFC34, 0x00A9);
+ r8168_mac_ocp_write(tp, 0xFC36, 0x012D);
+
rtl_hw_aspm_clkreq_enable(tp, true);
}
@@ -7102,13 +7239,18 @@ static int rtl_alloc_irq(struct rtl8169_private *tp)
{
unsigned int flags;
- if (tp->mac_version <= RTL_GIGA_MAC_VER_06) {
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06:
RTL_W8(tp, Cfg9346, Cfg9346_Unlock);
RTL_W8(tp, Config2, RTL_R8(tp, Config2) & ~MSIEnable);
RTL_W8(tp, Cfg9346, Cfg9346_Lock);
+ /* fall through */
+ case RTL_GIGA_MAC_VER_07 ... RTL_GIGA_MAC_VER_24:
flags = PCI_IRQ_LEGACY;
- } else {
+ break;
+ default:
flags = PCI_IRQ_ALL_TYPES;
+ break;
}
return pci_alloc_irq_vectors(tp->pci_dev, 1, 1, flags);
diff --git a/drivers/net/ethernet/sis/sis900.c b/drivers/net/ethernet/sis/sis900.c
index 4bb89f7..d5bcbc4 100644
--- a/drivers/net/ethernet/sis/sis900.c
+++ b/drivers/net/ethernet/sis/sis900.c
@@ -1057,7 +1057,7 @@ sis900_open(struct net_device *net_dev)
sis900_set_mode(sis_priv, HW_SPEED_10_MBPS, FDX_CAPABLE_HALF_SELECTED);
/* Enable all known interrupts by setting the interrupt mask. */
- sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE);
+ sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE | TxDESC);
sw32(cr, RxENA | sr32(cr));
sw32(ier, IE);
@@ -1578,7 +1578,7 @@ static void sis900_tx_timeout(struct net_device *net_dev)
sw32(txdp, sis_priv->tx_ring_dma);
/* Enable all known interrupts by setting the interrupt mask. */
- sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE);
+ sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE | TxDESC);
}
/**
@@ -1618,7 +1618,7 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
spin_unlock_irqrestore(&sis_priv->lock, flags);
return NETDEV_TX_OK;
}
- sis_priv->tx_ring[entry].cmdsts = (OWN | skb->len);
+ sis_priv->tx_ring[entry].cmdsts = (OWN | INTR | skb->len);
sw32(cr, TxENA | sr32(cr));
sis_priv->cur_tx ++;
@@ -1674,7 +1674,7 @@ static irqreturn_t sis900_interrupt(int irq, void *dev_instance)
do {
status = sr32(isr);
- if ((status & (HIBERR|TxURN|TxERR|TxIDLE|RxORN|RxERR|RxOK)) == 0)
+ if ((status & (HIBERR|TxURN|TxERR|TxIDLE|TxDESC|RxORN|RxERR|RxOK)) == 0)
/* nothing intresting happened */
break;
handled = 1;
@@ -1684,7 +1684,7 @@ static irqreturn_t sis900_interrupt(int irq, void *dev_instance)
/* Rx interrupt */
sis900_rx(net_dev);
- if (status & (TxURN | TxERR | TxIDLE))
+ if (status & (TxURN | TxERR | TxIDLE | TxDESC))
/* Tx interrupt */
sis900_finish_xmit(net_dev);
@@ -1896,8 +1896,8 @@ static void sis900_finish_xmit (struct net_device *net_dev)
if (tx_status & OWN) {
/* The packet is not transmitted yet (owned by hardware) !
- * Note: the interrupt is generated only when Tx Machine
- * is idle, so this is an almost impossible case */
+ * Note: this is an almost impossible condition
+ * in case of TxDESC ('descriptor interrupt') */
break;
}
@@ -2473,7 +2473,7 @@ static int sis900_resume(struct pci_dev *pci_dev)
sis900_set_mode(sis_priv, HW_SPEED_10_MBPS, FDX_CAPABLE_HALF_SELECTED);
/* Enable all known interrupts by setting the interrupt mask. */
- sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE);
+ sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE | TxDESC);
sw32(cr, RxENA | sr32(cr));
sw32(ier, IE);
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 272b9ca6..b069b3a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -261,7 +261,7 @@ struct stmmac_safety_stats {
#define STMMAC_COAL_TX_TIMER 1000
#define STMMAC_MAX_COAL_TX_TICK 100000
#define STMMAC_TX_MAX_FRAMES 256
-#define STMMAC_TX_FRAMES 25
+#define STMMAC_TX_FRAMES 1
/* Packets types */
enum packets_types {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
index 49a896a..79c9152 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
@@ -893,6 +893,11 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv)
* address. No need to mask it again.
*/
reg |= 1 << H3_EPHY_ADDR_SHIFT;
+ } else {
+ /* For SoCs without internal PHY the PHY selection bit should be
+ * set to 0 (external PHY).
+ */
+ reg &= ~H3_EPHY_SELECT;
}
if (!of_property_read_u32(node, "allwinner,tx-delay-ps", &val)) {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
index 0877bde..21d1313 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
@@ -216,6 +216,12 @@ static void dwmac1000_set_filter(struct mac_device_info *hw,
GMAC_ADDR_LOW(reg));
reg++;
}
+
+ while (reg <= perfect_addr_number) {
+ writel(0, ioaddr + GMAC_ADDR_HIGH(reg));
+ writel(0, ioaddr + GMAC_ADDR_LOW(reg));
+ reg++;
+ }
}
#ifdef FRAME_FILTER_DEBUG
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index 7e5d5db..d0e6e15 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -444,14 +444,20 @@ static void dwmac4_set_filter(struct mac_device_info *hw,
* are required
*/
value |= GMAC_PACKET_FILTER_PR;
- } else if (!netdev_uc_empty(dev)) {
- int reg = 1;
+ } else {
struct netdev_hw_addr *ha;
+ int reg = 1;
netdev_for_each_uc_addr(ha, dev) {
dwmac4_set_umac_addr(hw, ha->addr, reg);
reg++;
}
+
+ while (reg <= GMAC_MAX_PERFECT_ADDRESSES) {
+ writel(0, ioaddr + GMAC_ADDR_HIGH(reg));
+ writel(0, ioaddr + GMAC_ADDR_LOW(reg));
+ reg++;
+ }
}
writel(value, ioaddr + GMAC_PACKET_FILTER);
@@ -469,8 +475,9 @@ static void dwmac4_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,
if (fc & FLOW_RX) {
pr_debug("\tReceive Flow-Control ON\n");
flow |= GMAC_RX_FLOW_CTRL_RFE;
- writel(flow, ioaddr + GMAC_RX_FLOW_CTRL);
}
+ writel(flow, ioaddr + GMAC_RX_FLOW_CTRL);
+
if (fc & FLOW_TX) {
pr_debug("\tTransmit Flow-Control ON\n");
@@ -478,7 +485,7 @@ static void dwmac4_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,
pr_debug("\tduplex mode: PAUSE %d\n", pause_time);
for (queue = 0; queue < tx_cnt; queue++) {
- flow |= GMAC_TX_FLOW_CTRL_TFE;
+ flow = GMAC_TX_FLOW_CTRL_TFE;
if (duplex)
flow |=
@@ -486,6 +493,9 @@ static void dwmac4_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,
writel(flow, ioaddr + GMAC_QX_TX_FLOW_CTRL(queue));
}
+ } else {
+ for (queue = 0; queue < tx_cnt; queue++)
+ writel(0, ioaddr + GMAC_QX_TX_FLOW_CTRL(queue));
}
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 5c18874..0101eba 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -3036,17 +3036,8 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
/* Manage oversized TCP frames for GMAC4 device */
if (skb_is_gso(skb) && priv->tso) {
- if (skb_shinfo(skb)->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) {
- /*
- * There is no way to determine the number of TSO
- * capable Queues. Let's use always the Queue 0
- * because if TSO is supported then at least this
- * one will be capable.
- */
- skb_set_queue_mapping(skb, 0);
-
+ if (skb_shinfo(skb)->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))
return stmmac_tso_xmit(skb, dev);
- }
}
if (unlikely(stmmac_tx_avail(priv, queue) < nfrags + 1)) {
@@ -3855,6 +3846,23 @@ static int stmmac_setup_tc(struct net_device *ndev, enum tc_setup_type type,
}
}
+static u16 stmmac_select_queue(struct net_device *dev, struct sk_buff *skb,
+ struct net_device *sb_dev,
+ select_queue_fallback_t fallback)
+{
+ if (skb_shinfo(skb)->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) {
+ /*
+ * There is no way to determine the number of TSO
+ * capable Queues. Let's use always the Queue 0
+ * because if TSO is supported then at least this
+ * one will be capable.
+ */
+ return 0;
+ }
+
+ return fallback(dev, skb, NULL) % dev->real_num_tx_queues;
+}
+
static int stmmac_set_mac_address(struct net_device *ndev, void *addr)
{
struct stmmac_priv *priv = netdev_priv(ndev);
@@ -4097,6 +4105,7 @@ static const struct net_device_ops stmmac_netdev_ops = {
.ndo_tx_timeout = stmmac_tx_timeout,
.ndo_do_ioctl = stmmac_ioctl,
.ndo_setup_tc = stmmac_setup_tc,
+ .ndo_select_queue = stmmac_select_queue,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = stmmac_poll_controller,
#endif
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 7cfd7ff..66b30eb 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -614,6 +614,10 @@ static void axienet_start_xmit_done(struct net_device *ndev)
ndev->stats.tx_packets += packets;
ndev->stats.tx_bytes += size;
+
+ /* Matches barrier in axienet_start_xmit */
+ smp_mb();
+
netif_wake_queue(ndev);
}
@@ -668,9 +672,19 @@ static int axienet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
if (axienet_check_tx_bd_space(lp, num_frag)) {
- if (!netif_queue_stopped(ndev))
- netif_stop_queue(ndev);
- return NETDEV_TX_BUSY;
+ if (netif_queue_stopped(ndev))
+ return NETDEV_TX_BUSY;
+
+ netif_stop_queue(ndev);
+
+ /* Matches barrier in axienet_start_xmit_done */
+ smp_mb();
+
+ /* Space might have just been freed - check again */
+ if (axienet_check_tx_bd_space(lp, num_frag))
+ return NETDEV_TX_BUSY;
+
+ netif_wake_queue(ndev);
}
if (skb->ip_summed == CHECKSUM_PARTIAL) {
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 7a14517..d178d5b 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -289,16 +289,29 @@ static int gtp1u_udp_encap_recv(struct gtp_dev *gtp, struct sk_buff *skb)
return gtp_rx(pctx, skb, hdrlen, gtp->role);
}
-static void gtp_encap_destroy(struct sock *sk)
+static void __gtp_encap_destroy(struct sock *sk)
{
struct gtp_dev *gtp;
- gtp = rcu_dereference_sk_user_data(sk);
+ lock_sock(sk);
+ gtp = sk->sk_user_data;
if (gtp) {
+ if (gtp->sk0 == sk)
+ gtp->sk0 = NULL;
+ else
+ gtp->sk1u = NULL;
udp_sk(sk)->encap_type = 0;
rcu_assign_sk_user_data(sk, NULL);
sock_put(sk);
}
+ release_sock(sk);
+}
+
+static void gtp_encap_destroy(struct sock *sk)
+{
+ rtnl_lock();
+ __gtp_encap_destroy(sk);
+ rtnl_unlock();
}
static void gtp_encap_disable_sock(struct sock *sk)
@@ -306,7 +319,7 @@ static void gtp_encap_disable_sock(struct sock *sk)
if (!sk)
return;
- gtp_encap_destroy(sk);
+ __gtp_encap_destroy(sk);
}
static void gtp_encap_disable(struct gtp_dev *gtp)
@@ -800,7 +813,8 @@ static struct sock *gtp_encap_enable_socket(int fd, int type,
goto out_sock;
}
- if (rcu_dereference_sk_user_data(sock->sk)) {
+ lock_sock(sock->sk);
+ if (sock->sk->sk_user_data) {
sk = ERR_PTR(-EBUSY);
goto out_sock;
}
@@ -816,6 +830,7 @@ static struct sock *gtp_encap_enable_socket(int fd, int type,
setup_udp_tunnel_sock(sock_net(sock->sk), sock, &tuncfg);
out_sock:
+ release_sock(sock->sk);
sockfd_put(sock);
return sk;
}
@@ -847,8 +862,13 @@ static int gtp_encap_enable(struct gtp_dev *gtp, struct nlattr *data[])
if (data[IFLA_GTP_ROLE]) {
role = nla_get_u32(data[IFLA_GTP_ROLE]);
- if (role > GTP_ROLE_SGSN)
+ if (role > GTP_ROLE_SGSN) {
+ if (sk0)
+ gtp_encap_disable_sock(sk0);
+ if (sk1u)
+ gtp_encap_disable_sock(sk1u);
return -EINVAL;
+ }
}
gtp->sk0 = sk0;
@@ -949,7 +969,7 @@ static int ipv4_pdp_add(struct gtp_dev *gtp, struct sock *sk,
}
- pctx = kmalloc(sizeof(struct pdp_ctx), GFP_KERNEL);
+ pctx = kmalloc(sizeof(*pctx), GFP_ATOMIC);
if (pctx == NULL)
return -ENOMEM;
@@ -1038,6 +1058,7 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
return -EINVAL;
}
+ rtnl_lock();
rcu_read_lock();
gtp = gtp_find_dev(sock_net(skb->sk), info->attrs);
@@ -1062,6 +1083,7 @@ static int gtp_genl_new_pdp(struct sk_buff *skb, struct genl_info *info)
out_unlock:
rcu_read_unlock();
+ rtnl_unlock();
return err;
}
@@ -1363,9 +1385,9 @@ late_initcall(gtp_init);
static void __exit gtp_fini(void)
{
- unregister_pernet_subsys(>p_net_ops);
genl_unregister_family(>p_genl_family);
rtnl_link_unregister(>p_link_ops);
+ unregister_pernet_subsys(>p_net_ops);
pr_info("GTP module unloaded\n");
}
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index cf6b9b1..cc60ef9 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -847,7 +847,6 @@ int netvsc_recv_callback(struct net_device *net,
csum_info, vlan, data, len);
if (unlikely(!skb)) {
++net_device_ctx->eth_stats.rx_no_memory;
- rcu_read_unlock();
return NVSP_STAT_FAIL;
}
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index 7de88b3..2c97135 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -869,6 +869,7 @@ static void macsec_reset_skb(struct sk_buff *skb, struct net_device *dev)
static void macsec_finalize_skb(struct sk_buff *skb, u8 icv_len, u8 hdr_len)
{
+ skb->ip_summed = CHECKSUM_NONE;
memmove(skb->data + hdr_len, skb->data, 2 * ETH_ALEN);
skb_pull(skb, hdr_len);
pskb_trim_unique(skb, skb->len - icv_len);
@@ -1103,10 +1104,9 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb)
}
skb = skb_unshare(skb, GFP_ATOMIC);
- if (!skb) {
- *pskb = NULL;
+ *pskb = skb;
+ if (!skb)
return RX_HANDLER_CONSUMED;
- }
pulled_sci = pskb_may_pull(skb, macsec_extra_len(true));
if (!pulled_sci) {
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 8207079..1f5fd24 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -227,7 +227,7 @@
---help---
Currently supports the Aquantia AQ1202, AQ2104, AQR105, AQR405
-config ASIX_PHY
+config AX88796B_PHY
tristate "Asix PHYs"
help
Currently supports the Asix Electronics PHY found in the X-Surf 100
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 5805c0b..f21cda9 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -46,7 +46,7 @@
obj-$(CONFIG_AMD_PHY) += amd.o
obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o
-obj-$(CONFIG_ASIX_PHY) += asix.o
+obj-$(CONFIG_AX88796B_PHY) += ax88796b.o
obj-$(CONFIG_AT803X_PHY) += at803x.o
obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o
obj-$(CONFIG_BCM7XXX_PHY) += bcm7xxx.o
diff --git a/drivers/net/phy/asix.c b/drivers/net/phy/ax88796b.c
similarity index 100%
rename from drivers/net/phy/asix.c
rename to drivers/net/phy/ax88796b.c
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 8a96d98..6144146 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -757,6 +757,9 @@ int phy_connect_direct(struct net_device *dev, struct phy_device *phydev,
{
int rc;
+ if (!dev)
+ return -EINVAL;
+
rc = phy_attach_direct(dev, phydev, phydev->dev_flags, interface);
if (rc)
return rc;
@@ -1098,6 +1101,9 @@ struct phy_device *phy_attach(struct net_device *dev, const char *bus_id,
struct device *d;
int rc;
+ if (!dev)
+ return ERR_PTR(-EINVAL);
+
/* Search the list of PHY devices on the mdio bus for the
* PHY with the requested name
*/
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index e029c79..2e8056d 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -226,6 +226,8 @@ static int phylink_parse_fixedlink(struct phylink *pl,
__ETHTOOL_LINK_MODE_MASK_NBITS, true);
linkmode_zero(pl->supported);
phylink_set(pl->supported, MII);
+ phylink_set(pl->supported, Pause);
+ phylink_set(pl->supported, Asym_Pause);
if (s) {
__set_bit(s->bit, pl->supported);
} else {
diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
index 8807a80..998d08a 100644
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -185,10 +185,11 @@ struct sfp {
struct gpio_desc *gpio[GPIO_MAX];
bool attached;
+ struct mutex st_mutex; /* Protects state */
unsigned int state;
struct delayed_work poll;
struct delayed_work timeout;
- struct mutex sm_mutex;
+ struct mutex sm_mutex; /* Protects state machine */
unsigned char sm_mod_state;
unsigned char sm_dev_state;
unsigned short sm_state;
@@ -513,7 +514,7 @@ static int sfp_hwmon_read_sensor(struct sfp *sfp, int reg, long *value)
static void sfp_hwmon_to_rx_power(long *value)
{
- *value = DIV_ROUND_CLOSEST(*value, 100);
+ *value = DIV_ROUND_CLOSEST(*value, 10);
}
static void sfp_hwmon_calibrate(struct sfp *sfp, unsigned int slope, int offset,
@@ -1718,6 +1719,7 @@ static void sfp_check_state(struct sfp *sfp)
{
unsigned int state, i, changed;
+ mutex_lock(&sfp->st_mutex);
state = sfp_get_state(sfp);
changed = state ^ sfp->state;
changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT;
@@ -1743,6 +1745,7 @@ static void sfp_check_state(struct sfp *sfp)
sfp_sm_event(sfp, state & SFP_F_LOS ?
SFP_E_LOS_HIGH : SFP_E_LOS_LOW);
rtnl_unlock();
+ mutex_unlock(&sfp->st_mutex);
}
static irqreturn_t sfp_irq(int irq, void *data)
@@ -1773,6 +1776,7 @@ static struct sfp *sfp_alloc(struct device *dev)
sfp->dev = dev;
mutex_init(&sfp->sm_mutex);
+ mutex_init(&sfp->st_mutex);
INIT_DELAYED_WORK(&sfp->poll, sfp_poll);
INIT_DELAYED_WORK(&sfp->timeout, sfp_timeout);
diff --git a/drivers/net/ppp/ppp_mppe.c b/drivers/net/ppp/ppp_mppe.c
index 7ccdc62..06d620b 100644
--- a/drivers/net/ppp/ppp_mppe.c
+++ b/drivers/net/ppp/ppp_mppe.c
@@ -63,6 +63,7 @@ MODULE_AUTHOR("Frank Cusack <fcusack@fcusack.com>");
MODULE_DESCRIPTION("Point-to-Point Protocol Microsoft Point-to-Point Encryption support");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_ALIAS("ppp-compress-" __stringify(CI_MPPE));
+MODULE_SOFTDEP("pre: arc4");
MODULE_VERSION("1.0.2");
static unsigned int
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index f22639f..c04f3dc 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -1120,6 +1120,9 @@ static const struct proto_ops pppoe_ops = {
.recvmsg = pppoe_recvmsg,
.mmap = sock_no_mmap,
.ioctl = pppox_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = pppox_compat_ioctl,
+#endif
};
static const struct pppox_proto pppoe_proto = {
diff --git a/drivers/net/ppp/pppox.c b/drivers/net/ppp/pppox.c
index c0599b3..9128e42 100644
--- a/drivers/net/ppp/pppox.c
+++ b/drivers/net/ppp/pppox.c
@@ -22,6 +22,7 @@
#include <linux/string.h>
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/compat.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/net.h>
@@ -103,6 +104,18 @@ int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
EXPORT_SYMBOL(pppox_ioctl);
+#ifdef CONFIG_COMPAT
+int pppox_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ if (cmd == PPPOEIOCSFWD32)
+ cmd = PPPOEIOCSFWD;
+
+ return pppox_ioctl(sock, cmd, (unsigned long)compat_ptr(arg));
+}
+
+EXPORT_SYMBOL(pppox_compat_ioctl);
+#endif
+
static int pppox_create(struct net *net, struct socket *sock, int protocol,
int kern)
{
diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c
index 50c6055..b626001 100644
--- a/drivers/net/ppp/pptp.c
+++ b/drivers/net/ppp/pptp.c
@@ -628,6 +628,9 @@ static const struct proto_ops pptp_ops = {
.recvmsg = sock_no_recvmsg,
.mmap = sock_no_mmap,
.ioctl = pppox_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = pppox_compat_ioctl,
+#endif
};
static const struct pppox_proto pppox_pptp_proto = {
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 51a25be..2c80972 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1682,6 +1682,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun,
skb_reserve(skb, pad - delta);
skb_put(skb, len);
+ skb_set_owner_w(skb, tfile->socket.sk);
get_page(alloc_frag->page);
alloc_frag->offset += buflen;
diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c
index 3d93993..2eca416 100644
--- a/drivers/net/usb/asix_devices.c
+++ b/drivers/net/usb/asix_devices.c
@@ -238,7 +238,7 @@ static void asix_phy_reset(struct usbnet *dev, unsigned int reset_bits)
static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf)
{
int ret = 0;
- u8 buf[ETH_ALEN];
+ u8 buf[ETH_ALEN] = {0};
int i;
unsigned long gpio_bits = dev->driver_info->data;
@@ -689,7 +689,7 @@ static int asix_resume(struct usb_interface *intf)
static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
{
int ret, i;
- u8 buf[ETH_ALEN], chipcode = 0;
+ u8 buf[ETH_ALEN] = {0}, chipcode = 0;
u32 phyid;
struct asix_common_private *priv;
@@ -1073,7 +1073,7 @@ static const struct net_device_ops ax88178_netdev_ops = {
static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf)
{
int ret;
- u8 buf[ETH_ALEN];
+ u8 buf[ETH_ALEN] = {0};
usbnet_get_endpoints(dev,intf);
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index e657d89..128c8a3 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -153,7 +153,7 @@ static bool qmimux_has_slaves(struct usbnet *dev)
static int qmimux_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
- unsigned int len, offset = 0;
+ unsigned int len, offset = 0, pad_len, pkt_len;
struct qmimux_hdr *hdr;
struct net_device *net;
struct sk_buff *skbn;
@@ -171,10 +171,16 @@ static int qmimux_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
if (hdr->pad & 0x80)
goto skip;
+ /* extract padding length and check for valid length info */
+ pad_len = hdr->pad & 0x3f;
+ if (len == 0 || pad_len >= len)
+ goto skip;
+ pkt_len = len - pad_len;
+
net = qmimux_find_dev(dev, hdr->mux_id);
if (!net)
goto skip;
- skbn = netdev_alloc_skb(net, len);
+ skbn = netdev_alloc_skb(net, pkt_len);
if (!skbn)
return 0;
skbn->dev = net;
@@ -191,7 +197,7 @@ static int qmimux_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
goto skip;
}
- skb_put_data(skbn, skb->data + offset + qmimux_hdr_sz, len);
+ skb_put_data(skbn, skb->data + offset + qmimux_hdr_sz, pkt_len);
if (netif_rx(skbn) != NET_RX_SUCCESS)
return 0;
@@ -241,13 +247,14 @@ static int qmimux_register_device(struct net_device *real_dev, u8 mux_id)
return err;
}
-static void qmimux_unregister_device(struct net_device *dev)
+static void qmimux_unregister_device(struct net_device *dev,
+ struct list_head *head)
{
struct qmimux_priv *priv = netdev_priv(dev);
struct net_device *real_dev = priv->real_dev;
netdev_upper_dev_unlink(real_dev, dev);
- unregister_netdevice(dev);
+ unregister_netdevice_queue(dev, head);
/* Get rid of the reference to real_dev */
dev_put(real_dev);
@@ -356,8 +363,8 @@ static ssize_t add_mux_store(struct device *d, struct device_attribute *attr, c
if (kstrtou8(buf, 0, &mux_id))
return -EINVAL;
- /* mux_id [1 - 0x7f] range empirically found */
- if (mux_id < 1 || mux_id > 0x7f)
+ /* mux_id [1 - 254] for compatibility with ip(8) and the rmnet driver */
+ if (mux_id < 1 || mux_id > 254)
return -EINVAL;
if (!rtnl_trylock())
@@ -418,7 +425,7 @@ static ssize_t del_mux_store(struct device *d, struct device_attribute *attr, c
ret = -EINVAL;
goto err;
}
- qmimux_unregister_device(del_dev);
+ qmimux_unregister_device(del_dev, NULL);
if (!qmimux_has_slaves(dev))
info->flags &= ~QMI_WWAN_FLAG_MUX;
@@ -1428,6 +1435,7 @@ static void qmi_wwan_disconnect(struct usb_interface *intf)
struct qmi_wwan_state *info;
struct list_head *iter;
struct net_device *ldev;
+ LIST_HEAD(list);
/* called twice if separate control and data intf */
if (!dev)
@@ -1440,8 +1448,9 @@ static void qmi_wwan_disconnect(struct usb_interface *intf)
}
rcu_read_lock();
netdev_for_each_upper_dev_rcu(dev->net, ldev, iter)
- qmimux_unregister_device(ldev);
+ qmimux_unregister_device(ldev, &list);
rcu_read_unlock();
+ unregister_netdevice_many(&list);
rtnl_unlock();
info->flags &= ~QMI_WWAN_FLAG_MUX;
}
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index 449fc52..9f89508 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -169,23 +169,29 @@ static int vrf_ip6_local_out(struct net *net, struct sock *sk,
static netdev_tx_t vrf_process_v6_outbound(struct sk_buff *skb,
struct net_device *dev)
{
- const struct ipv6hdr *iph = ipv6_hdr(skb);
+ const struct ipv6hdr *iph;
struct net *net = dev_net(skb->dev);
- struct flowi6 fl6 = {
- /* needed to match OIF rule */
- .flowi6_oif = dev->ifindex,
- .flowi6_iif = LOOPBACK_IFINDEX,
- .daddr = iph->daddr,
- .saddr = iph->saddr,
- .flowlabel = ip6_flowinfo(iph),
- .flowi6_mark = skb->mark,
- .flowi6_proto = iph->nexthdr,
- .flowi6_flags = FLOWI_FLAG_SKIP_NH_OIF,
- };
+ struct flowi6 fl6;
int ret = NET_XMIT_DROP;
struct dst_entry *dst;
struct dst_entry *dst_null = &net->ipv6.ip6_null_entry->dst;
+ if (!pskb_may_pull(skb, ETH_HLEN + sizeof(struct ipv6hdr)))
+ goto err;
+
+ iph = ipv6_hdr(skb);
+
+ memset(&fl6, 0, sizeof(fl6));
+ /* needed to match OIF rule */
+ fl6.flowi6_oif = dev->ifindex;
+ fl6.flowi6_iif = LOOPBACK_IFINDEX;
+ fl6.daddr = iph->daddr;
+ fl6.saddr = iph->saddr;
+ fl6.flowlabel = ip6_flowinfo(iph);
+ fl6.flowi6_mark = skb->mark;
+ fl6.flowi6_proto = iph->nexthdr;
+ fl6.flowi6_flags = FLOWI_FLAG_SKIP_NH_OIF;
+
dst = ip6_route_output(net, NULL, &fl6);
if (dst == dst_null)
goto err;
@@ -241,21 +247,27 @@ static int vrf_ip_local_out(struct net *net, struct sock *sk,
static netdev_tx_t vrf_process_v4_outbound(struct sk_buff *skb,
struct net_device *vrf_dev)
{
- struct iphdr *ip4h = ip_hdr(skb);
+ struct iphdr *ip4h;
int ret = NET_XMIT_DROP;
- struct flowi4 fl4 = {
- /* needed to match OIF rule */
- .flowi4_oif = vrf_dev->ifindex,
- .flowi4_iif = LOOPBACK_IFINDEX,
- .flowi4_tos = RT_TOS(ip4h->tos),
- .flowi4_flags = FLOWI_FLAG_ANYSRC | FLOWI_FLAG_SKIP_NH_OIF,
- .flowi4_proto = ip4h->protocol,
- .daddr = ip4h->daddr,
- .saddr = ip4h->saddr,
- };
+ struct flowi4 fl4;
struct net *net = dev_net(vrf_dev);
struct rtable *rt;
+ if (!pskb_may_pull(skb, ETH_HLEN + sizeof(struct iphdr)))
+ goto err;
+
+ ip4h = ip_hdr(skb);
+
+ memset(&fl4, 0, sizeof(fl4));
+ /* needed to match OIF rule */
+ fl4.flowi4_oif = vrf_dev->ifindex;
+ fl4.flowi4_iif = LOOPBACK_IFINDEX;
+ fl4.flowi4_tos = RT_TOS(ip4h->tos);
+ fl4.flowi4_flags = FLOWI_FLAG_ANYSRC | FLOWI_FLAG_SKIP_NH_OIF;
+ fl4.flowi4_proto = ip4h->protocol;
+ fl4.daddr = ip4h->daddr;
+ fl4.saddr = ip4h->saddr;
+
rt = ip_route_output_flow(net, &fl4, NULL);
if (IS_ERR(rt))
goto err;
diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c
index 677535b..476e053 100644
--- a/drivers/net/wireless/ath/ath10k/hw.c
+++ b/drivers/net/wireless/ath/ath10k/hw.c
@@ -168,7 +168,7 @@ const struct ath10k_hw_values qca6174_values = {
};
const struct ath10k_hw_values qca99x0_values = {
- .rtc_state_val_on = 5,
+ .rtc_state_val_on = 7,
.ce_count = 12,
.msi_assign_ce_max = 12,
.num_target_ce_config_wlan = 10,
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index f3b1cfa..1419f9d 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -1624,6 +1624,10 @@ static int ath10k_mac_setup_prb_tmpl(struct ath10k_vif *arvif)
if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
return 0;
+ /* For mesh, probe response and beacon share the same template */
+ if (ieee80211_vif_is_mesh(vif))
+ return 0;
+
prb = ieee80211_proberesp_get(hw, vif);
if (!prb) {
ath10k_warn(ar, "failed to get probe resp template from mac80211\n");
diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index 7f61591..686759b 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -613,6 +613,10 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
full_len,
last_in_bundle,
last_in_bundle);
+ if (ret) {
+ ath10k_warn(ar, "alloc_rx_pkt error %d\n", ret);
+ goto err;
+ }
}
ar_sdio->n_rx_pkts = i;
@@ -2069,6 +2073,9 @@ static void ath10k_sdio_remove(struct sdio_func *func)
cancel_work_sync(&ar_sdio->wr_async_work);
ath10k_core_unregister(ar);
ath10k_core_destroy(ar);
+
+ flush_workqueue(ar_sdio->workqueue);
+ destroy_workqueue(ar_sdio->workqueue);
}
static const struct sdio_device_id ath10k_sdio_devices[] = {
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
index cda164f..6f62ddc 100644
--- a/drivers/net/wireless/ath/ath10k/txrx.c
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
@@ -156,6 +156,9 @@ struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar, int peer_id)
{
struct ath10k_peer *peer;
+ if (peer_id >= BITS_PER_TYPE(peer->peer_ids))
+ return NULL;
+
lockdep_assert_held(&ar->data_lock);
list_for_each_entry(peer, &ar->peers, list)
diff --git a/drivers/net/wireless/ath/ath10k/usb.c b/drivers/net/wireless/ath/ath10k/usb.c
index d4803ff..f09a4ad 100644
--- a/drivers/net/wireless/ath/ath10k/usb.c
+++ b/drivers/net/wireless/ath/ath10k/usb.c
@@ -1025,7 +1025,7 @@ static int ath10k_usb_probe(struct usb_interface *interface,
}
/* TODO: remove this once USB support is fully implemented */
- ath10k_warn(ar, "WARNING: ath10k USB support is incomplete, don't expect anything to work!\n");
+ ath10k_warn(ar, "Warning: ath10k USB support is incomplete, don't expect anything to work!\n");
return 0;
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 777acc5..bc7916f 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -1178,6 +1178,10 @@ static int ath6kl_wmi_pstream_timeout_event_rx(struct wmi *wmi, u8 *datap,
return -EINVAL;
ev = (struct wmi_pstream_timeout_event *) datap;
+ if (ev->traffic_class >= WMM_NUM_AC) {
+ ath6kl_err("invalid traffic class: %d\n", ev->traffic_class);
+ return -EINVAL;
+ }
/*
* When the pstream (fat pipe == AC) timesout, it means there were
@@ -1519,6 +1523,10 @@ static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len,
return -EINVAL;
reply = (struct wmi_cac_event *) datap;
+ if (reply->ac >= WMM_NUM_AC) {
+ ath6kl_err("invalid AC: %d\n", reply->ac);
+ return -EINVAL;
+ }
if ((reply->cac_indication == CAC_INDICATION_ADMISSION_RESP) &&
(reply->status_code != IEEE80211_TSPEC_STATUS_ADMISS_ACCEPTED)) {
@@ -2635,7 +2643,7 @@ int ath6kl_wmi_delete_pstream_cmd(struct wmi *wmi, u8 if_idx, u8 traffic_class,
u16 active_tsids = 0;
int ret;
- if (traffic_class > 3) {
+ if (traffic_class >= WMM_NUM_AC) {
ath6kl_err("invalid traffic class: %d\n", traffic_class);
return -EINVAL;
}
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index bb319f2..b4f7ee4 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -252,8 +252,9 @@ void ath9k_hw_get_channel_centers(struct ath_hw *ah,
/* Chip Revisions */
/******************/
-static void ath9k_hw_read_revisions(struct ath_hw *ah)
+static bool ath9k_hw_read_revisions(struct ath_hw *ah)
{
+ u32 srev;
u32 val;
if (ah->get_mac_revision)
@@ -269,25 +270,33 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah)
val = REG_READ(ah, AR_SREV);
ah->hw_version.macRev = MS(val, AR_SREV_REVISION2);
}
- return;
+ return true;
case AR9300_DEVID_AR9340:
ah->hw_version.macVersion = AR_SREV_VERSION_9340;
- return;
+ return true;
case AR9300_DEVID_QCA955X:
ah->hw_version.macVersion = AR_SREV_VERSION_9550;
- return;
+ return true;
case AR9300_DEVID_AR953X:
ah->hw_version.macVersion = AR_SREV_VERSION_9531;
- return;
+ return true;
case AR9300_DEVID_QCA956X:
ah->hw_version.macVersion = AR_SREV_VERSION_9561;
- return;
+ return true;
}
- val = REG_READ(ah, AR_SREV) & AR_SREV_ID;
+ srev = REG_READ(ah, AR_SREV);
+
+ if (srev == -EIO) {
+ ath_err(ath9k_hw_common(ah),
+ "Failed to read SREV register");
+ return false;
+ }
+
+ val = srev & AR_SREV_ID;
if (val == 0xFF) {
- val = REG_READ(ah, AR_SREV);
+ val = srev;
ah->hw_version.macVersion =
(val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S;
ah->hw_version.macRev = MS(val, AR_SREV_REVISION2);
@@ -306,6 +315,8 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah)
if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE)
ah->is_pciexpress = true;
}
+
+ return true;
}
/************************************/
@@ -559,7 +570,10 @@ static int __ath9k_hw_init(struct ath_hw *ah)
struct ath_common *common = ath9k_hw_common(ah);
int r = 0;
- ath9k_hw_read_revisions(ah);
+ if (!ath9k_hw_read_revisions(ah)) {
+ ath_err(common, "Could not read hardware revisions");
+ return -EOPNOTSUPP;
+ }
switch (ah->hw_version.macVersion) {
case AR_SREV_VERSION_5416_PCI:
diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c
index e7c3f3b..99f1897 100644
--- a/drivers/net/wireless/ath/carl9170/usb.c
+++ b/drivers/net/wireless/ath/carl9170/usb.c
@@ -128,6 +128,8 @@ static const struct usb_device_id carl9170_usb_ids[] = {
};
MODULE_DEVICE_TABLE(usb, carl9170_usb_ids);
+static struct usb_driver carl9170_driver;
+
static void carl9170_usb_submit_data_urb(struct ar9170 *ar)
{
struct urb *urb;
@@ -966,32 +968,28 @@ static int carl9170_usb_init_device(struct ar9170 *ar)
static void carl9170_usb_firmware_failed(struct ar9170 *ar)
{
- struct device *parent = ar->udev->dev.parent;
- struct usb_device *udev;
-
- /*
- * Store a copy of the usb_device pointer locally.
- * This is because device_release_driver initiates
- * carl9170_usb_disconnect, which in turn frees our
- * driver context (ar).
+ /* Store a copies of the usb_interface and usb_device pointer locally.
+ * This is because release_driver initiates carl9170_usb_disconnect,
+ * which in turn frees our driver context (ar).
*/
- udev = ar->udev;
+ struct usb_interface *intf = ar->intf;
+ struct usb_device *udev = ar->udev;
complete(&ar->fw_load_wait);
+ /* at this point 'ar' could be already freed. Don't use it anymore */
+ ar = NULL;
/* unbind anything failed */
- if (parent)
- device_lock(parent);
+ usb_lock_device(udev);
+ usb_driver_release_interface(&carl9170_driver, intf);
+ usb_unlock_device(udev);
- device_release_driver(&udev->dev);
- if (parent)
- device_unlock(parent);
-
- usb_put_dev(udev);
+ usb_put_intf(intf);
}
static void carl9170_usb_firmware_finish(struct ar9170 *ar)
{
+ struct usb_interface *intf = ar->intf;
int err;
err = carl9170_parse_firmware(ar);
@@ -1009,7 +1007,7 @@ static void carl9170_usb_firmware_finish(struct ar9170 *ar)
goto err_unrx;
complete(&ar->fw_load_wait);
- usb_put_dev(ar->udev);
+ usb_put_intf(intf);
return;
err_unrx:
@@ -1052,7 +1050,6 @@ static int carl9170_usb_probe(struct usb_interface *intf,
return PTR_ERR(ar);
udev = interface_to_usbdev(intf);
- usb_get_dev(udev);
ar->udev = udev;
ar->intf = intf;
ar->features = id->driver_info;
@@ -1094,15 +1091,14 @@ static int carl9170_usb_probe(struct usb_interface *intf,
atomic_set(&ar->rx_anch_urbs, 0);
atomic_set(&ar->rx_pool_urbs, 0);
- usb_get_dev(ar->udev);
+ usb_get_intf(intf);
carl9170_set_state(ar, CARL9170_STOPPED);
err = request_firmware_nowait(THIS_MODULE, 1, CARL9170FW_NAME,
&ar->udev->dev, GFP_KERNEL, ar, carl9170_usb_firmware_step2);
if (err) {
- usb_put_dev(udev);
- usb_put_dev(udev);
+ usb_put_intf(intf);
carl9170_free(ar);
}
return err;
@@ -1131,7 +1127,6 @@ static void carl9170_usb_disconnect(struct usb_interface *intf)
carl9170_release_firmware(ar);
carl9170_free(ar);
- usb_put_dev(udev);
}
#ifdef CONFIG_PM
diff --git a/drivers/net/wireless/ath/dfs_pattern_detector.c b/drivers/net/wireless/ath/dfs_pattern_detector.c
index d52b31b..a274eb0 100644
--- a/drivers/net/wireless/ath/dfs_pattern_detector.c
+++ b/drivers/net/wireless/ath/dfs_pattern_detector.c
@@ -111,7 +111,7 @@ static const struct radar_detector_specs jp_radar_ref_types[] = {
JP_PATTERN(0, 0, 1, 1428, 1428, 1, 18, 29, false),
JP_PATTERN(1, 2, 3, 3846, 3846, 1, 18, 29, false),
JP_PATTERN(2, 0, 1, 1388, 1388, 1, 18, 50, false),
- JP_PATTERN(3, 1, 2, 4000, 4000, 1, 18, 50, false),
+ JP_PATTERN(3, 0, 4, 4000, 4000, 1, 18, 50, false),
JP_PATTERN(4, 0, 5, 150, 230, 1, 23, 50, false),
JP_PATTERN(5, 6, 10, 200, 500, 1, 16, 50, false),
JP_PATTERN(6, 11, 20, 200, 500, 1, 12, 50, false),
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index 97d5933..7913124 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -299,6 +299,7 @@ static void wil_vif_init(struct wil6210_vif *vif)
INIT_WORK(&vif->probe_client_worker, wil_probe_client_worker);
INIT_WORK(&vif->disconnect_worker, wil_disconnect_worker);
+ INIT_WORK(&vif->p2p.discovery_expired_work, wil_p2p_listen_expired);
INIT_WORK(&vif->p2p.delayed_listen_work, wil_p2p_delayed_listen_work);
INIT_LIST_HEAD(&vif->probe_client_pending);
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index 3e90f4e..d7d761b 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -762,6 +762,7 @@ void wil_netif_rx(struct sk_buff *skb, struct net_device *ndev, int cid,
[GRO_HELD] = "GRO_HELD",
[GRO_NORMAL] = "GRO_NORMAL",
[GRO_DROP] = "GRO_DROP",
+ [GRO_CONSUMED] = "GRO_CONSUMED",
};
if (wdev->iftype == NL80211_IFTYPE_STATION) {
diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c
index b80d523..0215f59 100644
--- a/drivers/net/wireless/cnss2/main.c
+++ b/drivers/net/wireless/cnss2/main.c
@@ -29,6 +29,7 @@
#define FW_READY_TIMEOUT 20000
#define FW_ASSERT_TIMEOUT 5000
#define CNSS_EVENT_PENDING 2989
+#define COLD_BOOT_CAL_SHUTDOWN_DELAY_MS 50
#define CNSS_QUIRKS_DEFAULT 0
#ifdef CONFIG_CNSS_EMULATION
@@ -1254,6 +1255,7 @@ static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv,
cnss_wlfw_wlan_mode_send_sync(plat_priv, CNSS_OFF);
cnss_release_antenna_sharing(plat_priv);
cnss_bus_dev_shutdown(plat_priv);
+ msleep(COLD_BOOT_CAL_SHUTDOWN_DELAY_MS);
complete(&plat_priv->cal_complete);
clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c
index 15fcdb3..845ad97 100644
--- a/drivers/net/wireless/cnss2/pci.c
+++ b/drivers/net/wireless/cnss2/pci.c
@@ -16,6 +16,7 @@
#include "bus.h"
#include "debug.h"
#include "pci.h"
+#include "reg.h"
#define PCI_LINK_UP 1
#define PCI_LINK_DOWN 0
@@ -57,79 +58,10 @@ static DEFINE_SPINLOCK(pci_reg_window_lock);
#define MHI_TIMEOUT_OVERWRITE_MS (plat_priv->ctrl_params.mhi_timeout)
-#define QCA6390_PCIE_REMAP_BAR_CTRL_OFFSET 0x310C
-
-#define QCA6390_CE_SRC_RING_REG_BASE 0xA00000
-#define QCA6390_CE_DST_RING_REG_BASE 0xA01000
-#define QCA6390_CE_COMMON_REG_BASE 0xA18000
-
-#define QCA6390_CE_SRC_RING_BASE_LSB_OFFSET 0x0
-#define QCA6390_CE_SRC_RING_BASE_MSB_OFFSET 0x4
-#define QCA6390_CE_SRC_RING_ID_OFFSET 0x8
-#define QCA6390_CE_SRC_RING_MISC_OFFSET 0x10
-#define QCA6390_CE_SRC_CTRL_OFFSET 0x58
-#define QCA6390_CE_SRC_R0_CE_CH_SRC_IS_OFFSET 0x5C
-#define QCA6390_CE_SRC_RING_HP_OFFSET 0x400
-#define QCA6390_CE_SRC_RING_TP_OFFSET 0x404
-
-#define QCA6390_CE_DEST_RING_BASE_LSB_OFFSET 0x0
-#define QCA6390_CE_DEST_RING_BASE_MSB_OFFSET 0x4
-#define QCA6390_CE_DEST_RING_ID_OFFSET 0x8
-#define QCA6390_CE_DEST_RING_MISC_OFFSET 0x10
-#define QCA6390_CE_DEST_CTRL_OFFSET 0xB0
-#define QCA6390_CE_CH_DST_IS_OFFSET 0xB4
-#define QCA6390_CE_CH_DEST_CTRL2_OFFSET 0xB8
-#define QCA6390_CE_DEST_RING_HP_OFFSET 0x400
-#define QCA6390_CE_DEST_RING_TP_OFFSET 0x404
-
-#define QCA6390_CE_STATUS_RING_BASE_LSB_OFFSET 0x58
-#define QCA6390_CE_STATUS_RING_BASE_MSB_OFFSET 0x5C
-#define QCA6390_CE_STATUS_RING_ID_OFFSET 0x60
-#define QCA6390_CE_STATUS_RING_MISC_OFFSET 0x68
-#define QCA6390_CE_STATUS_RING_HP_OFFSET 0x408
-#define QCA6390_CE_STATUS_RING_TP_OFFSET 0x40C
-
-#define QCA6390_CE_COMMON_GXI_ERR_INTS 0x14
-#define QCA6390_CE_COMMON_GXI_ERR_STATS 0x18
-#define QCA6390_CE_COMMON_GXI_WDOG_STATUS 0x2C
-#define QCA6390_CE_COMMON_TARGET_IE_0 0x48
-#define QCA6390_CE_COMMON_TARGET_IE_1 0x4C
-
-#define QCA6390_CE_REG_INTERVAL 0x2000
-
-#define SHADOW_REG_COUNT 36
-#define QCA6390_PCIE_SHADOW_REG_VALUE_0 0x8FC
-#define QCA6390_PCIE_SHADOW_REG_VALUE_34 0x984
-#define QCA6390_PCIE_SHADOW_REG_VALUE_35 0x988
-#define QCA6390_WLAON_GLOBAL_COUNTER_CTRL3 0x1F80118
-#define QCA6390_WLAON_GLOBAL_COUNTER_CTRL4 0x1F8011C
-#define QCA6390_WLAON_GLOBAL_COUNTER_CTRL5 0x1F80120
-
-#define SHADOW_REG_INTER_COUNT 43
-#define QCA6390_PCIE_SHADOW_REG_INTER_0 0x1E05000
-#define QCA6390_PCIE_SHADOW_REG_HUNG 0x1E050A8
-
-#define QDSS_APB_DEC_CSR_BASE 0x1C01000
-
-#define QDSS_APB_DEC_CSR_ETRIRQCTRL_OFFSET 0x6C
-#define QDSS_APB_DEC_CSR_PRESERVEETF_OFFSET 0x70
-#define QDSS_APB_DEC_CSR_PRESERVEETR0_OFFSET 0x74
-#define QDSS_APB_DEC_CSR_PRESERVEETR1_OFFSET 0x78
-
-#define MAX_UNWINDOWED_ADDRESS 0x80000
-#define WINDOW_ENABLE_BIT 0x40000000
-#define WINDOW_SHIFT 19
-#define WINDOW_VALUE_MASK 0x3F
-#define WINDOW_START MAX_UNWINDOWED_ADDRESS
-#define WINDOW_RANGE_MASK 0x7FFFF
-
#define FORCE_WAKE_DELAY_MIN_US 4000
#define FORCE_WAKE_DELAY_MAX_US 6000
#define FORCE_WAKE_DELAY_TIMEOUT_US 60000
-#define QCA6390_TIME_SYNC_ENABLE 0x80000000
-#define QCA6390_TIME_SYNC_CLEAR 0x0
-
static struct cnss_pci_reg ce_src[] = {
{ "SRC_RING_BASE_LSB", QCA6390_CE_SRC_RING_BASE_LSB_OFFSET },
{ "SRC_RING_BASE_MSB", QCA6390_CE_SRC_RING_BASE_MSB_OFFSET },
@@ -178,6 +110,240 @@ static struct cnss_pci_reg qdss_csr[] = {
{ NULL },
};
+static struct cnss_misc_reg wcss_reg_access_seq[] = {
+ {0, QCA6390_GCC_DEBUG_CLK_CTL, 0},
+ {1, QCA6390_GCC_DEBUG_CLK_CTL, 0x802},
+ {0, QCA6390_GCC_DEBUG_CLK_CTL, 0},
+ {0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_PLL_MODE, 0},
+ {1, QCA6390_GCC_DEBUG_CLK_CTL, 0x805},
+ {0, QCA6390_GCC_DEBUG_CLK_CTL, 0},
+ {0, QCA6390_WCSS_WFSS_PMM_WFSS_PMM_R0_PMM_CTRL, 0},
+ {0, QCA6390_WCSS_PMM_TOP_PMU_CX_CSR, 0},
+ {0, QCA6390_WCSS_PMM_TOP_AON_INT_RAW_STAT, 0},
+ {0, QCA6390_WCSS_PMM_TOP_AON_INT_EN, 0},
+ {0, QCA6390_WCSS_PMM_TOP_PMU_TESTBUS_STS, 0},
+ {1, QCA6390_WCSS_PMM_TOP_PMU_TESTBUS_CTL, 0xD},
+ {0, QCA6390_WCSS_PMM_TOP_TESTBUS_STS, 0},
+ {0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_CFG, 0},
+ {1, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_CFG, 0},
+ {1, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_CTL, 0x8},
+ {0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_VALUE, 0},
+ {0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_SPM_STS, 0},
+ {0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_SPM_CTL, 0},
+ {0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_SPM_SLP_SEQ_ENTRY_0, 0},
+ {0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_SPM_SLP_SEQ_ENTRY_9, 0},
+ {0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS0, 0},
+ {0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS1, 0},
+ {0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS2, 0},
+ {0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS3, 0},
+ {0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS4, 0},
+ {0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS5, 0},
+ {0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS6, 0},
+ {0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE0, 0},
+ {0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE1, 0},
+ {0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE2, 0},
+ {0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE3, 0},
+ {0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE4, 0},
+ {0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE5, 0},
+ {0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE6, 0},
+ {0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING0, 0},
+ {0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING1, 0},
+ {0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING2, 0},
+ {0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING3, 0},
+ {0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING4, 0},
+ {0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING5, 0},
+ {0, QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING6, 0},
+ {1, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_CTL, 0x30040},
+ {0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_CTL, 0},
+ {0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_VALUE, 0},
+ {0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_VALUE, 0},
+ {0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_VALUE, 0},
+ {1, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_CTL, 0x30105},
+ {0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_CTL, 0},
+ {0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_VALUE, 0},
+ {0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_VALUE, 0},
+ {0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_VALUE, 0},
+ {0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_VALUE, 0},
+ {0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_VALUE, 0},
+ {0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_VALUE, 0},
+ {0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_VALUE, 0},
+ {0, QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_CTL, 0},
+ {0, QCA6390_WCSS_CC_WCSS_UMAC_NOC_CBCR, 0},
+ {0, QCA6390_WCSS_CC_WCSS_UMAC_AHB_CBCR, 0},
+ {0, QCA6390_WCSS_CC_WCSS_UMAC_GDSCR, 0},
+ {0, QCA6390_WCSS_CC_WCSS_WLAN1_GDSCR, 0},
+ {0, QCA6390_WCSS_CC_WCSS_WLAN2_GDSCR, 0},
+ {0, QCA6390_WCSS_PMM_TOP_PMM_INT_CLR, 0},
+ {0, QCA6390_WCSS_PMM_TOP_AON_INT_STICKY_EN, 0},
+};
+
+static struct cnss_misc_reg pcie_reg_access_seq[] = {
+ {0, QCA6390_PCIE_PCIE_WCSS_STATUS_FOR_DEBUG_LOW_PCIE_LOCAL_REG, 0},
+ {0, QCA6390_PCIE_SOC_PCIE_WRAP_INTR_MASK_SOC_PCIE_REG, 0},
+ {1, QCA6390_PCIE_SOC_PCIE_WRAP_INTR_MASK_SOC_PCIE_REG, 0x18},
+ {0, QCA6390_PCIE_SOC_PCIE_WRAP_INTR_MASK_SOC_PCIE_REG, 0},
+ {0, QCA6390_PCIE_SOC_PCIE_WRAP_INTR_MASK_SOC_PCIE_REG, 0},
+ {0, QCA6390_PCIE_SOC_PCIE_WRAP_INTR_STATUS_SOC_PCIE_REG, 0},
+ {0, QCA6390_PCIE_SOC_COMMIT_REPLAY_SOC_PCIE_REG, 0},
+ {0, QCA6390_TLMM_GPIO_IN_OUT57, 0},
+ {0, QCA6390_TLMM_GPIO_INTR_CFG57, 0},
+ {0, QCA6390_TLMM_GPIO_INTR_STATUS57, 0},
+ {0, QCA6390_TLMM_GPIO_IN_OUT59, 0},
+ {0, QCA6390_TLMM_GPIO_INTR_CFG59, 0},
+ {0, QCA6390_TLMM_GPIO_INTR_STATUS59, 0},
+ {0, QCA6390_PCIE_PCIE_PARF_LTSSM, 0},
+ {0, QCA6390_PCIE_PCIE_PARF_PM_STTS, 0},
+ {0, QCA6390_PCIE_PCIE_PARF_PM_STTS_1, 0},
+ {0, QCA6390_PCIE_PCIE_PARF_INT_STATUS, 0},
+ {0, QCA6390_PCIE_PCIE_INT_ALL_STATUS, 0},
+ {0, QCA6390_PCIE_PCIE_INT_ALL_MASK, 0},
+ {0, QCA6390_PCIE_PCIE_PARF_BDF_TO_SID_CFG, 0},
+ {0, QCA6390_PCIE_PCIE_PARF_L1SS_SLEEP_NO_MHI_ACCESS_HANDLER_RD_4, 0},
+ {0, QCA6390_PCIE_PCIE_PARF_L1SS_SLEEP_NO_MHI_ACCESS_HANDLER_RD_3, 0},
+ {0, QCA6390_PCIE_PCIE_PARF_MHI_CLOCK_RESET_CTRL, 0},
+ {0, QCA6390_PCIE_PCIE_PARF_MHI_BASE_ADDR_LOWER, 0},
+ {0, QCA6390_PCIE_PCIE_PARF_L1SS_SLEEP_MODE_HANDLER_STATUS, 0},
+ {0, QCA6390_PCIE_PCIE_PARF_L1SS_SLEEP_MODE_HANDLER_CFG, 0},
+ {0, QCA6390_PCIE_PCIE_PARF_DEBUG_CNT_AUX_CLK_IN_L1SUB_L2, 0},
+ {0, QCA6390_PCIE_PCIE_PARF_DEBUG_CNT_PM_LINKST_IN_L1SUB, 0},
+ {0, QCA6390_PCIE_PCIE_CORE_CONFIG, 0},
+ {0, QCA6390_PCIE_PCIE_PARF_L1SS_SLEEP_NO_MHI_ACCESS_HANDLER_RD_4, 0},
+ {0, QCA6390_PCIE_PCIE_PARF_DEBUG_CNT_PM_LINKST_IN_L2, 0},
+ {0, QCA6390_PCIE_PCIE_PARF_DEBUG_CNT_PM_LINKST_IN_L1, 0},
+ {0, QCA6390_PCIE_PCIE_PARF_DEBUG_CNT_AUX_CLK_IN_L1SUB_L1, 0},
+ {0, QCA6390_PCIE_PCIE_PARF_DEBUG_CNT_AUX_CLK_IN_L1SUB_L2, 0},
+ {0, QCA6390_PCIE_PCIE_LOCAL_REG_WCSSAON_PCIE_SR_STATUS_HIGH, 0},
+ {0, QCA6390_PCIE_PCIE_LOCAL_REG_WCSSAON_PCIE_SR_STATUS_LOW, 0},
+ {0, QCA6390_PCIE_PCIE_LOCAL_REG_WCSS_STATUS_FOR_DEBUG_HIGH, 0},
+ {0, QCA6390_PCIE_PCIE_LOCAL_REG_WCSS_STATUS_FOR_DEBUG_LOW, 0},
+ {0, QCA6390_WFSS_PMM_WFSS_PMM_R0_WLAN1_STATUS_REG2, 0},
+ {0, QCA6390_WFSS_PMM_WFSS_PMM_R0_WLAN2_STATUS_REG2, 0},
+ {0, QCA6390_WFSS_PMM_WFSS_PMM_R0_PMM_WLAN2_CFG_REG1, 0},
+ {0, QCA6390_WFSS_PMM_WFSS_PMM_R0_PMM_WLAN1_CFG_REG1, 0},
+ {0, QCA6390_WFSS_PMM_WFSS_PMM_R0_WLAN2_APS_STATUS_REG1, 0},
+ {0, QCA6390_WFSS_PMM_WFSS_PMM_R0_WLAN1_APS_STATUS_REG1, 0},
+};
+
+static struct cnss_misc_reg wlaon_reg_access_seq[] = {
+ {0, QCA6390_WLAON_WCSSAON_PCIE_SR_STATUS_HI_REG, 0},
+ {0, QCA6390_WLAON_SOC_POWER_CTRL, 0},
+ {0, QCA6390_WLAON_PCIE_PWR_CTRL_REG, 0},
+ {0, QCA6390_WLAON_WCSSAON_PCIE_SR_STATUS_LO_REG, 0},
+ {0, QCA6390_WLAON_WCSS_TCSR_PMM_SR_STATUS_HI_REG, 0},
+ {0, QCA6390_WLAON_WCSS_TCSR_PMM_SR_STATUS_LO_REG, 0},
+ {0, QCA6390_WLAON_SOC_POWER_CTRL, 0},
+ {0, QCA6390_WLAON_SOC_PWR_WDG_BARK_THRSHD, 0},
+ {0, QCA6390_WLAON_SOC_PWR_WDG_BITE_THRSHD, 0},
+ {0, QCA6390_WLAON_SW_COLD_RESET, 0},
+ {0, QCA6390_WLAON_RFA_MEM_SLP_NRET_N_OVERRIDE, 0},
+ {0, QCA6390_WLAON_GDSC_DELAY_SETTING, 0},
+ {0, QCA6390_WLAON_GDSC_DELAY_SETTING2, 0},
+ {0, QCA6390_WLAON_WL_PWR_STATUS_REG, 0},
+ {0, QCA6390_WLAON_WL_AON_DBG_CFG_REG, 0},
+ {0, QCA6390_WLAON_GLOBAL_COUNTER_CTRL1, 0},
+ {0, QCA6390_WLAON_GLOBAL_COUNTER_CTRL6, 0},
+ {0, QCA6390_WLAON_GLOBAL_COUNTER_CTRL7, 0},
+ {0, QCA6390_WLAON_GLOBAL_COUNTER_CTRL3, 0},
+ {0, QCA6390_WLAON_GLOBAL_COUNTER_CTRL4, 0},
+ {0, QCA6390_WLAON_GLOBAL_COUNTER_CTRL5, 0},
+ {0, QCA6390_WLAON_GLOBAL_COUNTER_CTRL8, 0},
+ {0, QCA6390_WLAON_GLOBAL_COUNTER_CTRL2, 0},
+ {0, QCA6390_WLAON_GLOBAL_COUNTER_CTRL9, 0},
+ {0, QCA6390_WLAON_RTC_CLK_CAL_CTRL1, 0},
+ {0, QCA6390_WLAON_RTC_CLK_CAL_CTRL2, 0},
+ {0, QCA6390_WLAON_RTC_CLK_CAL_CTRL3, 0},
+ {0, QCA6390_WLAON_RTC_CLK_CAL_CTRL4, 0},
+ {0, QCA6390_WLAON_RTC_CLK_CAL_CTRL5, 0},
+ {0, QCA6390_WLAON_RTC_CLK_CAL_CTRL6, 0},
+ {0, QCA6390_WLAON_RTC_CLK_CAL_CTRL7, 0},
+ {0, QCA6390_WLAON_RTC_CLK_CAL_CTRL8, 0},
+ {0, QCA6390_WLAON_RTC_CLK_CAL_CTRL9, 0},
+ {0, QCA6390_WLAON_WCSSAON_CONFIG_REG, 0},
+ {0, QCA6390_WLAON_WLAN_OEM_DEBUG_REG, 0},
+ {0, QCA6390_WLAON_WLAN_RAM_DUMP_REG, 0},
+ {0, QCA6390_WLAON_QDSS_WCSS_REG, 0},
+ {0, QCA6390_WLAON_QDSS_WCSS_ACK, 0},
+ {0, QCA6390_WLAON_WL_CLK_CNTL_KDF_REG, 0},
+ {0, QCA6390_WLAON_WL_CLK_CNTL_PMU_HFRC_REG, 0},
+ {0, QCA6390_WLAON_QFPROM_PWR_CTRL_REG, 0},
+ {0, QCA6390_WLAON_DLY_CONFIG, 0},
+ {0, QCA6390_WLAON_WLAON_Q6_IRQ_REG, 0},
+ {0, QCA6390_WLAON_PCIE_INTF_SW_CFG_REG, 0},
+ {0, QCA6390_WLAON_PCIE_INTF_STICKY_SW_CFG_REG, 0},
+ {0, QCA6390_WLAON_PCIE_INTF_PHY_SW_CFG_REG, 0},
+ {0, QCA6390_WLAON_PCIE_INTF_PHY_NOCSR_SW_CFG_REG, 0},
+ {0, QCA6390_WLAON_Q6_COOKIE_BIT, 0},
+ {0, QCA6390_WLAON_WARM_SW_ENTRY, 0},
+ {0, QCA6390_WLAON_RESET_DBG_SW_ENTRY, 0},
+ {0, QCA6390_WLAON_WL_PMUNOC_CFG_REG, 0},
+ {0, QCA6390_WLAON_RESET_CAUSE_CFG_REG, 0},
+ {0, QCA6390_WLAON_SOC_WCSSAON_WAKEUP_IRQ_7_EN_REG, 0},
+ {0, QCA6390_WLAON_DEBUG, 0},
+ {0, QCA6390_WLAON_SOC_PARAMETERS, 0},
+ {0, QCA6390_WLAON_WLPM_SIGNAL, 0},
+ {0, QCA6390_WLAON_SOC_RESET_CAUSE_REG, 0},
+ {0, QCA6390_WLAON_WAKEUP_PCIE_SOC_REG, 0},
+ {0, QCA6390_WLAON_PBL_STACK_CANARY, 0},
+ {0, QCA6390_WLAON_MEM_TOT_NUM_GRP_REG, 0},
+ {0, QCA6390_WLAON_MEM_TOT_BANKS_IN_GRP0_REG, 0},
+ {0, QCA6390_WLAON_MEM_TOT_BANKS_IN_GRP1_REG, 0},
+ {0, QCA6390_WLAON_MEM_TOT_BANKS_IN_GRP2_REG, 0},
+ {0, QCA6390_WLAON_MEM_TOT_BANKS_IN_GRP3_REG, 0},
+ {0, QCA6390_WLAON_MEM_TOT_SIZE_IN_GRP0_REG, 0},
+ {0, QCA6390_WLAON_MEM_TOT_SIZE_IN_GRP1_REG, 0},
+ {0, QCA6390_WLAON_MEM_TOT_SIZE_IN_GRP2_REG, 0},
+ {0, QCA6390_WLAON_MEM_TOT_SIZE_IN_GRP3_REG, 0},
+ {0, QCA6390_WLAON_MEM_SLP_NRET_OVERRIDE_GRP0_REG, 0},
+ {0, QCA6390_WLAON_MEM_SLP_NRET_OVERRIDE_GRP1_REG, 0},
+ {0, QCA6390_WLAON_MEM_SLP_NRET_OVERRIDE_GRP2_REG, 0},
+ {0, QCA6390_WLAON_MEM_SLP_NRET_OVERRIDE_GRP3_REG, 0},
+ {0, QCA6390_WLAON_MEM_SLP_RET_OVERRIDE_GRP0_REG, 0},
+ {0, QCA6390_WLAON_MEM_SLP_RET_OVERRIDE_GRP1_REG, 0},
+ {0, QCA6390_WLAON_MEM_SLP_RET_OVERRIDE_GRP2_REG, 0},
+ {0, QCA6390_WLAON_MEM_SLP_RET_OVERRIDE_GRP3_REG, 0},
+ {0, QCA6390_WLAON_MEM_CNT_SEL_REG, 0},
+ {0, QCA6390_WLAON_MEM_NO_EXTBHS_REG, 0},
+ {0, QCA6390_WLAON_MEM_DEBUG_REG, 0},
+ {0, QCA6390_WLAON_MEM_DEBUG_BUS_REG, 0},
+ {0, QCA6390_WLAON_MEM_REDUN_CFG_REG, 0},
+ {0, QCA6390_WLAON_WL_AON_SPARE2, 0},
+ {0, QCA6390_WLAON_VSEL_CFG_FOR_WL_RET_DISABLE_REG, 0},
+ {0, QCA6390_WLAON_BTFM_WLAN_IPC_STATUS_REG, 0},
+ {0, QCA6390_WLAON_MPM_COUNTER_CHICKEN_BITS, 0},
+ {0, QCA6390_WLAON_WLPM_CHICKEN_BITS, 0},
+ {0, QCA6390_WLAON_PCIE_PHY_PWR_REG, 0},
+ {0, QCA6390_WLAON_WL_CLK_CNTL_PMU_LPO2M_REG, 0},
+ {0, QCA6390_WLAON_WL_SS_ROOT_CLK_SWITCH_REG, 0},
+ {0, QCA6390_WLAON_POWERCTRL_PMU_REG, 0},
+ {0, QCA6390_WLAON_POWERCTRL_MEM_REG, 0},
+ {0, QCA6390_WLAON_PCIE_PWR_CTRL_REG, 0},
+ {0, QCA6390_WLAON_SOC_PWR_PROFILE_REG, 0},
+ {0, QCA6390_WLAON_WCSSAON_PCIE_SR_STATUS_HI_REG, 0},
+ {0, QCA6390_WLAON_WCSSAON_PCIE_SR_STATUS_LO_REG, 0},
+ {0, QCA6390_WLAON_WCSS_TCSR_PMM_SR_STATUS_HI_REG, 0},
+ {0, QCA6390_WLAON_WCSS_TCSR_PMM_SR_STATUS_LO_REG, 0},
+ {0, QCA6390_WLAON_MEM_SVS_CFG_REG, 0},
+ {0, QCA6390_WLAON_CMN_AON_MISC_REG, 0},
+ {0, QCA6390_WLAON_INTR_STATUS, 0},
+ {0, QCA6390_SYSPM_SYSPM_PWR_STATUS, 0},
+ {0, QCA6390_SYSPM_DBG_BTFM_AON_REG, 0},
+ {0, QCA6390_SYSPM_DBG_BUS_SEL_REG, 0},
+ {0, QCA6390_SYSPM_WCSSAON_SR_STATUS, 0},
+ {0, QCA6390_SYSPM_WCSSAON_SR_STATUS, 0},
+ {0, QCA6390_SYSPM_WCSSAON_SR_STATUS, 0},
+ {0, QCA6390_SYSPM_WCSSAON_SR_STATUS, 0},
+ {0, QCA6390_SYSPM_WCSSAON_SR_STATUS, 0},
+ {0, QCA6390_SYSPM_WCSSAON_SR_STATUS, 0},
+ {0, QCA6390_SYSPM_WCSSAON_SR_STATUS, 0},
+ {0, QCA6390_SYSPM_WCSSAON_SR_STATUS, 0},
+ {0, QCA6390_SYSPM_WCSSAON_SR_STATUS, 0},
+ {0, QCA6390_SYSPM_WCSSAON_SR_STATUS, 0},
+};
+
+#define WCSS_REG_SIZE ARRAY_SIZE(wcss_reg_access_seq)
+#define PCIE_REG_SIZE ARRAY_SIZE(pcie_reg_access_seq)
+#define WLAON_REG_SIZE ARRAY_SIZE(wlaon_reg_access_seq)
+
static int cnss_pci_check_link_status(struct cnss_pci_data *pci_priv)
{
u16 device_id;
@@ -1090,6 +1256,74 @@ int cnss_pci_update_status(struct cnss_pci_data *pci_priv,
return 0;
}
+static void cnss_pci_misc_reg_dump(struct cnss_pci_data *pci_priv,
+ struct cnss_misc_reg *misc_reg,
+ u32 misc_reg_size,
+ char *reg_name)
+{
+ int i;
+
+ if (!misc_reg)
+ return;
+
+ if (in_interrupt() || irqs_disabled())
+ return;
+
+ if (cnss_pci_check_link_status(pci_priv))
+ return;
+
+ cnss_pci_force_wake_get(pci_priv);
+
+ cnss_pr_dbg("start to dump %s registers\n", reg_name);
+
+ for (i = 0; i < misc_reg_size; i++) {
+ if (misc_reg[i].wr) {
+ if (misc_reg[i].offset ==
+ QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_CFG &&
+ i >= 1)
+ misc_reg[i].val =
+ QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_CFG_MSK |
+ misc_reg[i - 1].val;
+ if (cnss_pci_reg_write(pci_priv,
+ misc_reg[i].offset,
+ misc_reg[i].val))
+ goto force_wake_put;
+ cnss_pr_vdbg("Write 0x%X to 0x%X\n",
+ misc_reg[i].val,
+ misc_reg[i].offset);
+
+ } else {
+ if (cnss_pci_reg_read(pci_priv,
+ misc_reg[i].offset,
+ &misc_reg[i].val))
+ goto force_wake_put;
+ cnss_pr_vdbg("Read 0x%X from 0x%X\n",
+ misc_reg[i].val,
+ misc_reg[i].offset);
+ }
+ }
+
+force_wake_put:
+ cnss_pci_force_wake_put(pci_priv);
+}
+
+static void cnss_pci_dump_misc_reg(struct cnss_pci_data *pci_priv)
+{
+ if (in_interrupt() || irqs_disabled())
+ return;
+
+ if (cnss_pci_check_link_status(pci_priv))
+ return;
+
+ mhi_debug_reg_dump(pci_priv->mhi_ctrl);
+ cnss_pci_misc_reg_dump(pci_priv, pci_priv->wcss_reg,
+ pci_priv->wcss_reg_size, "wcss");
+ cnss_pci_misc_reg_dump(pci_priv, pci_priv->pcie_reg,
+ pci_priv->pcie_reg_size, "pcie");
+ cnss_pci_misc_reg_dump(pci_priv, pci_priv->wlaon_reg,
+ pci_priv->wlaon_reg_size, "wlaon");
+}
+
static void cnss_pci_dump_shadow_reg(struct cnss_pci_data *pci_priv)
{
int i, j = 0, array_size = SHADOW_REG_COUNT + SHADOW_REG_INTER_COUNT;
@@ -1691,6 +1925,8 @@ static void cnss_pci_event_cb(struct msm_pcie_notify *notify)
break;
case MSM_PCIE_EVENT_DRV_DISCONNECT:
cnss_pr_dbg("DRV subsystem is disconnected\n");
+ cnss_pci_pm_runtime_get(pci_priv);
+ cnss_pci_pm_runtime_put_noidle(pci_priv);
cnss_pci_set_drv_connected(pci_priv, 0);
break;
default:
@@ -1730,15 +1966,129 @@ static void cnss_dereg_pci_event(struct cnss_pci_data *pci_priv)
msm_pcie_deregister_event(&pci_priv->msm_pci_event);
}
+static int cnss_pci_suspend_driver(struct cnss_pci_data *pci_priv)
+{
+ struct pci_dev *pci_dev = pci_priv->pci_dev;
+ struct cnss_wlan_driver *driver_ops = pci_priv->driver_ops;
+ int ret = 0;
+
+ pm_message_t state = { .event = PM_EVENT_SUSPEND };
+
+ if (driver_ops && driver_ops->suspend) {
+ ret = driver_ops->suspend(pci_dev, state);
+ if (ret) {
+ cnss_pr_err("Failed to suspend host driver, err = %d\n",
+ ret);
+ ret = -EAGAIN;
+ }
+ }
+
+ return ret;
+}
+
+static int cnss_pci_resume_driver(struct cnss_pci_data *pci_priv)
+{
+ struct pci_dev *pci_dev = pci_priv->pci_dev;
+ struct cnss_wlan_driver *driver_ops = pci_priv->driver_ops;
+ int ret = 0;
+
+ if (driver_ops && driver_ops->resume) {
+ ret = driver_ops->resume(pci_dev);
+ if (ret)
+ cnss_pr_err("Failed to resume host driver, err = %d\n",
+ ret);
+ }
+
+ return ret;
+}
+
+static int cnss_pci_suspend_bus(struct cnss_pci_data *pci_priv)
+{
+ struct pci_dev *pci_dev = pci_priv->pci_dev;
+ int ret = 0;
+
+ if (pci_priv->pci_link_state == PCI_LINK_DOWN)
+ goto out;
+
+ if (cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_SUSPEND)) {
+ ret = -EAGAIN;
+ goto out;
+ }
+
+ if (pci_priv->drv_connected_last)
+ goto skip_disable_pci;
+
+ pci_clear_master(pci_dev);
+ cnss_set_pci_config_space(pci_priv, SAVE_PCI_CONFIG_SPACE);
+ pci_disable_device(pci_dev);
+
+ ret = pci_set_power_state(pci_dev, PCI_D3hot);
+ if (ret)
+ cnss_pr_err("Failed to set D3Hot, err = %d\n", ret);
+
+skip_disable_pci:
+ if (cnss_set_pci_link(pci_priv, PCI_LINK_DOWN)) {
+ ret = -EAGAIN;
+ goto resume_mhi;
+ }
+ pci_priv->pci_link_state = PCI_LINK_DOWN;
+
+ return 0;
+
+resume_mhi:
+ if (!pci_is_enabled(pci_dev))
+ if (pci_enable_device(pci_dev))
+ cnss_pr_err("Failed to enable PCI device\n");
+ if (pci_priv->saved_state)
+ cnss_set_pci_config_space(pci_priv, RESTORE_PCI_CONFIG_SPACE);
+ pci_set_master(pci_dev);
+ cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RESUME);
+out:
+ return ret;
+}
+
+static int cnss_pci_resume_bus(struct cnss_pci_data *pci_priv)
+{
+ struct pci_dev *pci_dev = pci_priv->pci_dev;
+ int ret = 0;
+
+ if (pci_priv->pci_link_state == PCI_LINK_UP)
+ goto out;
+
+ if (cnss_set_pci_link(pci_priv, PCI_LINK_UP)) {
+ cnss_fatal_err("Failed to resume PCI link from suspend\n");
+ cnss_pci_link_down(&pci_dev->dev);
+ ret = -EAGAIN;
+ goto out;
+ }
+
+ if (pci_priv->drv_connected_last)
+ goto skip_enable_pci;
+
+ ret = pci_enable_device(pci_dev);
+ if (ret) {
+ cnss_pr_err("Failed to enable PCI device, err = %d\n",
+ ret);
+ goto out;
+ }
+
+ if (pci_priv->saved_state)
+ cnss_set_pci_config_space(pci_priv,
+ RESTORE_PCI_CONFIG_SPACE);
+ pci_set_master(pci_dev);
+
+skip_enable_pci:
+ cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RESUME);
+ pci_priv->pci_link_state = PCI_LINK_UP;
+out:
+ return ret;
+}
+
static int cnss_pci_suspend(struct device *dev)
{
int ret = 0;
- struct pci_dev *pci_dev = to_pci_dev(dev);
- struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
+ struct cnss_pci_data *pci_priv = cnss_get_pci_priv(to_pci_dev(dev));
struct cnss_plat_data *plat_priv;
- struct cnss_wlan_driver *driver_ops;
-
- pm_message_t state = { .event = PM_EVENT_SUSPEND };
if (!pci_priv)
goto out;
@@ -1750,62 +2100,34 @@ static int cnss_pci_suspend(struct device *dev)
if (!cnss_is_device_powered_on(plat_priv))
goto out;
- set_bit(CNSS_IN_SUSPEND_RESUME, &plat_priv->driver_state);
-
- if (!test_bit(DISABLE_DRV, &plat_priv->ctrl_params.quirks))
+ if (!test_bit(DISABLE_DRV, &plat_priv->ctrl_params.quirks)) {
pci_priv->drv_connected_last =
cnss_pci_get_drv_connected(pci_priv);
-
- driver_ops = pci_priv->driver_ops;
- if (driver_ops && driver_ops->suspend) {
- ret = driver_ops->suspend(pci_dev, state);
- if (ret) {
- cnss_pr_err("Failed to suspend host driver, err = %d\n",
- ret);
+ if (!pci_priv->drv_connected_last) {
+ cnss_pr_dbg("Firmware does not support non-DRV suspend, reject\n");
ret = -EAGAIN;
- goto clear_flag;
+ goto out;
}
}
- if (pci_priv->pci_link_state == PCI_LINK_UP && !pci_priv->disable_pc) {
- if (cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_SUSPEND)) {
- ret = -EAGAIN;
- goto resume_driver;
- }
+ set_bit(CNSS_IN_SUSPEND_RESUME, &plat_priv->driver_state);
- if (pci_priv->drv_connected_last)
- goto skip_disable_pci;
+ ret = cnss_pci_suspend_driver(pci_priv);
+ if (ret)
+ goto clear_flag;
- pci_clear_master(pci_dev);
- cnss_set_pci_config_space(pci_priv, SAVE_PCI_CONFIG_SPACE);
- pci_disable_device(pci_dev);
-
- ret = pci_set_power_state(pci_dev, PCI_D3hot);
+ if (!pci_priv->disable_pc) {
+ ret = cnss_pci_suspend_bus(pci_priv);
if (ret)
- cnss_pr_err("Failed to set D3Hot, err = %d\n", ret);
-
-skip_disable_pci:
- if (cnss_set_pci_link(pci_priv, PCI_LINK_DOWN)) {
- ret = -EAGAIN;
- goto resume_mhi;
- }
- pci_priv->pci_link_state = PCI_LINK_DOWN;
+ goto resume_driver;
}
cnss_pci_set_monitor_wake_intr(pci_priv, false);
return 0;
-resume_mhi:
- if (pci_enable_device(pci_dev))
- cnss_pr_err("Failed to enable PCI device\n");
- if (pci_priv->saved_state)
- cnss_set_pci_config_space(pci_priv, RESTORE_PCI_CONFIG_SPACE);
- pci_set_master(pci_dev);
- cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RESUME);
resume_driver:
- if (driver_ops && driver_ops->resume)
- driver_ops->resume(pci_dev);
+ cnss_pci_resume_driver(pci_priv);
clear_flag:
pci_priv->drv_connected_last = 0;
clear_bit(CNSS_IN_SUSPEND_RESUME, &plat_priv->driver_state);
@@ -1819,7 +2141,6 @@ static int cnss_pci_resume(struct device *dev)
struct pci_dev *pci_dev = to_pci_dev(dev);
struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
struct cnss_plat_data *plat_priv;
- struct cnss_wlan_driver *driver_ops;
if (!pci_priv)
goto out;
@@ -1834,40 +2155,13 @@ static int cnss_pci_resume(struct device *dev)
if (!cnss_is_device_powered_on(pci_priv->plat_priv))
goto out;
- if (pci_priv->pci_link_state == PCI_LINK_DOWN &&
- !pci_priv->disable_pc) {
- if (cnss_set_pci_link(pci_priv, PCI_LINK_UP)) {
- cnss_fatal_err("Failed to resume PCI link from suspend\n");
- cnss_pci_link_down(dev);
- ret = -EAGAIN;
+ if (!pci_priv->disable_pc) {
+ ret = cnss_pci_resume_bus(pci_priv);
+ if (ret)
goto out;
- }
- pci_priv->pci_link_state = PCI_LINK_UP;
-
- if (pci_priv->drv_connected_last)
- goto skip_enable_pci;
-
- ret = pci_enable_device(pci_dev);
- if (ret)
- cnss_pr_err("Failed to enable PCI device, err = %d\n",
- ret);
-
- if (pci_priv->saved_state)
- cnss_set_pci_config_space(pci_priv,
- RESTORE_PCI_CONFIG_SPACE);
- pci_set_master(pci_dev);
-
-skip_enable_pci:
- cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RESUME);
}
- driver_ops = pci_priv->driver_ops;
- if (driver_ops && driver_ops->resume) {
- ret = driver_ops->resume(pci_dev);
- if (ret)
- cnss_pr_err("Failed to resume host driver, err = %d\n",
- ret);
- }
+ ret = cnss_pci_resume_driver(pci_priv);
pci_priv->drv_connected_last = 0;
clear_bit(CNSS_IN_SUSPEND_RESUME, &plat_priv->driver_state);
@@ -1936,11 +2230,16 @@ static int cnss_pci_runtime_suspend(struct device *dev)
return -EAGAIN;
}
- cnss_pr_vdbg("Runtime suspend start\n");
-
- if (!test_bit(DISABLE_DRV, &plat_priv->ctrl_params.quirks))
+ if (!test_bit(DISABLE_DRV, &plat_priv->ctrl_params.quirks)) {
pci_priv->drv_connected_last =
cnss_pci_get_drv_connected(pci_priv);
+ if (!pci_priv->drv_connected_last) {
+ cnss_pr_dbg("Firmware does not support non-DRV suspend, reject\n");
+ return -EAGAIN;
+ }
+ }
+
+ cnss_pr_vdbg("Runtime suspend start\n");
driver_ops = pci_priv->driver_ops;
if (driver_ops && driver_ops->runtime_ops &&
@@ -2039,46 +2338,74 @@ void cnss_pci_pm_runtime_show_usage_count(struct cnss_pci_data *pci_priv)
int cnss_pci_pm_request_resume(struct cnss_pci_data *pci_priv)
{
- struct pci_dev *pci_dev;
+ struct device *dev;
+ enum rpm_status status;
if (!pci_priv)
return -ENODEV;
- pci_dev = pci_priv->pci_dev;
- if (!pci_dev)
- return -ENODEV;
+ dev = &pci_priv->pci_dev->dev;
- return pm_request_resume(&pci_dev->dev);
+ status = dev->power.runtime_status;
+ if (status == RPM_SUSPENDING || status == RPM_SUSPENDED)
+ cnss_pr_vdbg("Runtime PM resume is requested by %ps\n",
+ (void *)_RET_IP_);
+
+ return pm_request_resume(dev);
}
int cnss_pci_pm_runtime_resume(struct cnss_pci_data *pci_priv)
{
- struct pci_dev *pci_dev;
+ struct device *dev;
+ enum rpm_status status;
if (!pci_priv)
return -ENODEV;
- pci_dev = pci_priv->pci_dev;
- if (!pci_dev)
- return -ENODEV;
+ dev = &pci_priv->pci_dev->dev;
- return pm_runtime_resume(&pci_dev->dev);
+ status = dev->power.runtime_status;
+ if (status == RPM_SUSPENDING || status == RPM_SUSPENDED)
+ cnss_pr_vdbg("Runtime PM resume is requested by %ps\n",
+ (void *)_RET_IP_);
+
+ return pm_runtime_resume(dev);
}
int cnss_pci_pm_runtime_get(struct cnss_pci_data *pci_priv)
{
+ struct device *dev;
+ enum rpm_status status;
+
if (!pci_priv)
return -ENODEV;
- return pm_runtime_get(&pci_priv->pci_dev->dev);
+ dev = &pci_priv->pci_dev->dev;
+
+ status = dev->power.runtime_status;
+ if (status == RPM_SUSPENDING || status == RPM_SUSPENDED)
+ cnss_pr_vdbg("Runtime PM resume is requested by %ps\n",
+ (void *)_RET_IP_);
+
+ return pm_runtime_get(dev);
}
int cnss_pci_pm_runtime_get_sync(struct cnss_pci_data *pci_priv)
{
+ struct device *dev;
+ enum rpm_status status;
+
if (!pci_priv)
return -ENODEV;
- return pm_runtime_get_sync(&pci_priv->pci_dev->dev);
+ dev = &pci_priv->pci_dev->dev;
+
+ status = dev->power.runtime_status;
+ if (status == RPM_SUSPENDING || status == RPM_SUSPENDED)
+ cnss_pr_vdbg("Runtime PM resume is requested by %ps\n",
+ (void *)_RET_IP_);
+
+ return pm_runtime_get_sync(dev);
}
void cnss_pci_pm_runtime_get_noresume(struct cnss_pci_data *pci_priv)
@@ -2086,7 +2413,7 @@ void cnss_pci_pm_runtime_get_noresume(struct cnss_pci_data *pci_priv)
if (!pci_priv)
return;
- return pm_runtime_get_noresume(&pci_priv->pci_dev->dev);
+ pm_runtime_get_noresume(&pci_priv->pci_dev->dev);
}
int cnss_pci_pm_runtime_put_autosuspend(struct cnss_pci_data *pci_priv)
@@ -2146,31 +2473,9 @@ int cnss_auto_suspend(struct device *dev)
if (!plat_priv)
return -ENODEV;
- if (pci_priv->pci_link_state == PCI_LINK_UP) {
- if (cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_SUSPEND)) {
- ret = -EAGAIN;
- goto out;
- }
-
- if (pci_priv->drv_connected_last)
- goto skip_disable_pci;
-
- pci_clear_master(pci_dev);
- cnss_set_pci_config_space(pci_priv, SAVE_PCI_CONFIG_SPACE);
- pci_disable_device(pci_dev);
-
- ret = pci_set_power_state(pci_dev, PCI_D3hot);
- if (ret)
- cnss_pr_err("Failed to set D3Hot, err = %d\n", ret);
-
-skip_disable_pci:
- if (cnss_set_pci_link(pci_priv, PCI_LINK_DOWN)) {
- ret = -EAGAIN;
- goto resume_mhi;
- }
-
- pci_priv->pci_link_state = PCI_LINK_DOWN;
- }
+ ret = cnss_pci_suspend_bus(pci_priv);
+ if (ret)
+ return ret;
cnss_pci_set_auto_suspended(pci_priv, 1);
cnss_pci_set_monitor_wake_intr(pci_priv, true);
@@ -2180,13 +2485,6 @@ int cnss_auto_suspend(struct device *dev)
CNSS_BUS_WIDTH_NONE);
return 0;
-
-resume_mhi:
- if (pci_enable_device(pci_dev))
- cnss_pr_err("Failed to enable PCI device!\n");
- cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RESUME);
-out:
- return ret;
}
EXPORT_SYMBOL(cnss_auto_suspend);
@@ -2205,37 +2503,17 @@ int cnss_auto_resume(struct device *dev)
if (!plat_priv)
return -ENODEV;
- if (pci_priv->pci_link_state == PCI_LINK_DOWN) {
- if (cnss_set_pci_link(pci_priv, PCI_LINK_UP)) {
- cnss_fatal_err("Failed to resume PCI link from suspend\n");
- cnss_pci_link_down(dev);
- ret = -EAGAIN;
- goto out;
- }
- pci_priv->pci_link_state = PCI_LINK_UP;
-
- if (pci_priv->drv_connected_last)
- goto skip_enable_pci;
-
- ret = pci_enable_device(pci_dev);
- if (ret)
- cnss_pr_err("Failed to enable PCI device, err = %d\n",
- ret);
-
- cnss_set_pci_config_space(pci_priv, RESTORE_PCI_CONFIG_SPACE);
- pci_set_master(pci_dev);
-
-skip_enable_pci:
- cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_RESUME);
- }
+ ret = cnss_pci_resume_bus(pci_priv);
+ if (ret)
+ return ret;
cnss_pci_set_auto_suspended(pci_priv, 0);
bus_bw_info = &plat_priv->bus_bw_info;
msm_bus_scale_client_update_request(bus_bw_info->bus_client,
bus_bw_info->current_bw_vote);
-out:
- return ret;
+
+ return 0;
}
EXPORT_SYMBOL(cnss_auto_resume);
@@ -2493,6 +2771,7 @@ int cnss_pci_force_fw_assert_hdlr(struct cnss_pci_data *pci_priv)
return -ENODEV;
cnss_auto_resume(&pci_priv->pci_dev->dev);
+ cnss_pci_dump_misc_reg(pci_priv);
cnss_pci_dump_shadow_reg(pci_priv);
ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_TRIGGER_RDDM);
@@ -3029,6 +3308,7 @@ void cnss_pci_collect_dump_info(struct cnss_pci_data *pci_priv, bool in_panic)
if (cnss_pci_check_link_status(pci_priv))
return;
+ cnss_pci_dump_misc_reg(pci_priv);
cnss_pci_dump_qdss_reg(pci_priv);
ret = mhi_download_rddm_img(pci_priv->mhi_ctrl, in_panic);
@@ -3132,6 +3412,8 @@ static char *cnss_mhi_notify_status_to_str(enum MHI_CB status)
return "SYS_ERROR";
case MHI_CB_FATAL_ERROR:
return "FATAL_ERROR";
+ case MHI_CB_EE_MISSION_MODE:
+ return "MISSION_MODE";
default:
return "UNKNOWN";
}
@@ -3182,6 +3464,7 @@ static void cnss_mhi_notify_status(struct mhi_controller *mhi_ctrl, void *priv,
switch (reason) {
case MHI_CB_IDLE:
+ case MHI_CB_EE_MISSION_MODE:
return;
case MHI_CB_FATAL_ERROR:
set_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state);
@@ -3345,6 +3628,31 @@ static void cnss_pci_unregister_mhi(struct cnss_pci_data *pci_priv)
kfree(mhi_ctrl->irq);
}
+static void cnss_pci_config_regs(struct cnss_pci_data *pci_priv)
+{
+ switch (pci_priv->device_id) {
+ case QCA6390_DEVICE_ID:
+ pci_priv->wcss_reg = wcss_reg_access_seq;
+ pci_priv->wcss_reg_size = WCSS_REG_SIZE;
+ pci_priv->pcie_reg = pcie_reg_access_seq;
+ pci_priv->pcie_reg_size = PCIE_REG_SIZE;
+ pci_priv->wlaon_reg = wlaon_reg_access_seq;
+ pci_priv->wlaon_reg_size = WLAON_REG_SIZE;
+
+ /* Configure WDOG register with specific value so that we can
+ * know if HW is in the process of WDOG reset recovery or not
+ * when reading the registers.
+ */
+ cnss_pci_reg_write
+ (pci_priv,
+ QCA6390_PCIE_SOC_WDOG_DISC_BAD_DATA_LOW_CFG_SOC_PCIE_REG,
+ QCA6390_PCIE_SOC_WDOG_DISC_BAD_DATA_LOW_CFG_SOC_PCIE_REG_VAL);
+ break;
+ default:
+ return;
+ }
+}
+
static int cnss_pci_probe(struct pci_dev *pci_dev,
const struct pci_device_id *id)
{
@@ -3426,6 +3734,9 @@ static int cnss_pci_probe(struct pci_dev *pci_dev,
goto disable_bus;
}
cnss_pci_get_link_status(pci_priv);
+
+ cnss_pci_config_regs(pci_priv);
+
if (EMULATION_HW)
break;
ret = cnss_suspend_pci_link(pci_priv);
diff --git a/drivers/net/wireless/cnss2/pci.h b/drivers/net/wireless/cnss2/pci.h
index 0858b27..8dcb14a6 100644
--- a/drivers/net/wireless/cnss2/pci.h
+++ b/drivers/net/wireless/cnss2/pci.h
@@ -53,6 +53,12 @@ struct cnss_pci_debug_reg {
u32 val;
};
+struct cnss_misc_reg {
+ u8 wr;
+ u32 offset;
+ u32 val;
+};
+
struct cnss_pci_data {
struct pci_dev *pci_dev;
struct cnss_plat_data *plat_priv;
@@ -87,6 +93,12 @@ struct cnss_pci_data {
struct delayed_work time_sync_work;
u8 disable_pc;
struct cnss_pci_debug_reg *debug_reg;
+ struct cnss_misc_reg *wcss_reg;
+ u32 wcss_reg_size;
+ struct cnss_misc_reg *pcie_reg;
+ u32 pcie_reg_size;
+ struct cnss_misc_reg *wlaon_reg;
+ u32 wlaon_reg_size;
};
static inline void cnss_set_pci_priv(struct pci_dev *pci_dev, void *data)
diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c
index 89e12659..3513d15 100644
--- a/drivers/net/wireless/cnss2/qmi.c
+++ b/drivers/net/wireless/cnss2/qmi.c
@@ -432,6 +432,56 @@ int cnss_wlfw_tgt_cap_send_sync(struct cnss_plat_data *plat_priv)
return ret;
}
+static int cnss_get_bdf_file_name(struct cnss_plat_data *plat_priv,
+ u32 bdf_type, char *filename,
+ u32 filename_len)
+{
+ int ret = 0;
+
+ switch (bdf_type) {
+ case CNSS_BDF_ELF:
+ if (plat_priv->board_info.board_id == 0xFF)
+ snprintf(filename, filename_len, ELF_BDF_FILE_NAME);
+ else if (plat_priv->board_info.board_id < 0xFF)
+ snprintf(filename, filename_len,
+ ELF_BDF_FILE_NAME_PREFIX "%02x",
+ plat_priv->board_info.board_id);
+ else
+ snprintf(filename, filename_len,
+ BDF_FILE_NAME_PREFIX "%02x.e%02x",
+ plat_priv->board_info.board_id >> 8 & 0xFF,
+ plat_priv->board_info.board_id & 0xFF);
+ break;
+ case CNSS_BDF_BIN:
+ if (plat_priv->board_info.board_id == 0xFF)
+ snprintf(filename, filename_len, BIN_BDF_FILE_NAME);
+ else if (plat_priv->board_info.board_id < 0xFF)
+ snprintf(filename, filename_len,
+ BIN_BDF_FILE_NAME_PREFIX "%02x",
+ plat_priv->board_info.board_id);
+ else
+ snprintf(filename, filename_len,
+ BDF_FILE_NAME_PREFIX "%02x.b%02x",
+ plat_priv->board_info.board_id >> 8 & 0xFF,
+ plat_priv->board_info.board_id & 0xFF);
+ break;
+ case CNSS_BDF_REGDB:
+ snprintf(filename, filename_len, REGDB_FILE_NAME);
+ break;
+ case CNSS_BDF_DUMMY:
+ cnss_pr_dbg("CNSS_BDF_DUMMY is set, sending dummy BDF\n");
+ snprintf(filename, filename_len, DUMMY_BDF_FILE_NAME);
+ ret = MAX_BDF_FILE_NAME;
+ break;
+ default:
+ cnss_pr_err("Invalid BDF type: %d\n",
+ plat_priv->ctrl_params.bdf_type);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv,
u32 bdf_type)
{
@@ -457,46 +507,13 @@ int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv,
return -ENOMEM;
}
- switch (bdf_type) {
- case CNSS_BDF_ELF:
- if (plat_priv->board_info.board_id == 0xFF)
- snprintf(filename, sizeof(filename), ELF_BDF_FILE_NAME);
- else if (plat_priv->board_info.board_id < 0xFF)
- snprintf(filename, sizeof(filename),
- ELF_BDF_FILE_NAME_PREFIX "%02x",
- plat_priv->board_info.board_id);
- else
- snprintf(filename, sizeof(filename),
- BDF_FILE_NAME_PREFIX "%02x.e%02x",
- plat_priv->board_info.board_id >> 8 & 0xFF,
- plat_priv->board_info.board_id & 0xFF);
- break;
- case CNSS_BDF_BIN:
- if (plat_priv->board_info.board_id == 0xFF)
- snprintf(filename, sizeof(filename), BIN_BDF_FILE_NAME);
- else if (plat_priv->board_info.board_id < 0xFF)
- snprintf(filename, sizeof(filename),
- BIN_BDF_FILE_NAME_PREFIX "%02x",
- plat_priv->board_info.board_id);
- else
- snprintf(filename, sizeof(filename),
- BDF_FILE_NAME_PREFIX "%02x.b%02x",
- plat_priv->board_info.board_id >> 8 & 0xFF,
- plat_priv->board_info.board_id & 0xFF);
- break;
- case CNSS_BDF_REGDB:
- snprintf(filename, sizeof(filename), REGDB_FILE_NAME);
- break;
- case CNSS_BDF_DUMMY:
- cnss_pr_dbg("CNSS_BDF_DUMMY is set, sending dummy BDF\n");
- snprintf(filename, sizeof(filename), DUMMY_BDF_FILE_NAME);
+ ret = cnss_get_bdf_file_name(plat_priv, bdf_type,
+ filename, sizeof(filename));
+ if (ret > 0) {
temp = DUMMY_BDF_FILE_NAME;
remaining = MAX_BDF_FILE_NAME;
goto bypass_bdf;
- default:
- cnss_pr_err("Invalid BDF type: %d\n",
- plat_priv->ctrl_params.bdf_type);
- ret = -EINVAL;
+ } else if (ret < 0) {
goto err_req_fw;
}
diff --git a/drivers/net/wireless/cnss2/reg.h b/drivers/net/wireless/cnss2/reg.h
new file mode 100644
index 0000000..4052de4
--- /dev/null
+++ b/drivers/net/wireless/cnss2/reg.h
@@ -0,0 +1,267 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (c) 2019, The Linux Foundation. All rights reserved. */
+
+#ifndef _CNSS_REG_H
+#define _CNSS_REG_H
+
+#define QCA6390_PCIE_REMAP_BAR_CTRL_OFFSET 0x310C
+
+#define QCA6390_CE_SRC_RING_REG_BASE 0xA00000
+#define QCA6390_CE_DST_RING_REG_BASE 0xA01000
+#define QCA6390_CE_COMMON_REG_BASE 0xA18000
+
+#define QCA6390_CE_SRC_RING_BASE_LSB_OFFSET 0x0
+#define QCA6390_CE_SRC_RING_BASE_MSB_OFFSET 0x4
+#define QCA6390_CE_SRC_RING_ID_OFFSET 0x8
+#define QCA6390_CE_SRC_RING_MISC_OFFSET 0x10
+#define QCA6390_CE_SRC_CTRL_OFFSET 0x58
+#define QCA6390_CE_SRC_R0_CE_CH_SRC_IS_OFFSET 0x5C
+#define QCA6390_CE_SRC_RING_HP_OFFSET 0x400
+#define QCA6390_CE_SRC_RING_TP_OFFSET 0x404
+
+#define QCA6390_CE_DEST_RING_BASE_LSB_OFFSET 0x0
+#define QCA6390_CE_DEST_RING_BASE_MSB_OFFSET 0x4
+#define QCA6390_CE_DEST_RING_ID_OFFSET 0x8
+#define QCA6390_CE_DEST_RING_MISC_OFFSET 0x10
+#define QCA6390_CE_DEST_CTRL_OFFSET 0xB0
+#define QCA6390_CE_CH_DST_IS_OFFSET 0xB4
+#define QCA6390_CE_CH_DEST_CTRL2_OFFSET 0xB8
+#define QCA6390_CE_DEST_RING_HP_OFFSET 0x400
+#define QCA6390_CE_DEST_RING_TP_OFFSET 0x404
+
+#define QCA6390_CE_STATUS_RING_BASE_LSB_OFFSET 0x58
+#define QCA6390_CE_STATUS_RING_BASE_MSB_OFFSET 0x5C
+#define QCA6390_CE_STATUS_RING_ID_OFFSET 0x60
+#define QCA6390_CE_STATUS_RING_MISC_OFFSET 0x68
+#define QCA6390_CE_STATUS_RING_HP_OFFSET 0x408
+#define QCA6390_CE_STATUS_RING_TP_OFFSET 0x40C
+
+#define QCA6390_CE_COMMON_GXI_ERR_INTS 0x14
+#define QCA6390_CE_COMMON_GXI_ERR_STATS 0x18
+#define QCA6390_CE_COMMON_GXI_WDOG_STATUS 0x2C
+#define QCA6390_CE_COMMON_TARGET_IE_0 0x48
+#define QCA6390_CE_COMMON_TARGET_IE_1 0x4C
+
+#define QCA6390_CE_REG_INTERVAL 0x2000
+
+#define SHADOW_REG_COUNT 36
+#define QCA6390_PCIE_SHADOW_REG_VALUE_0 0x8FC
+#define QCA6390_PCIE_SHADOW_REG_VALUE_34 0x984
+#define QCA6390_PCIE_SHADOW_REG_VALUE_35 0x988
+#define QCA6390_WLAON_GLOBAL_COUNTER_CTRL3 0x1F80118
+#define QCA6390_WLAON_GLOBAL_COUNTER_CTRL4 0x1F8011C
+#define QCA6390_WLAON_GLOBAL_COUNTER_CTRL5 0x1F80120
+
+#define SHADOW_REG_INTER_COUNT 43
+#define QCA6390_PCIE_SHADOW_REG_INTER_0 0x1E05000
+#define QCA6390_PCIE_SHADOW_REG_HUNG 0x1E050A8
+
+#define QDSS_APB_DEC_CSR_BASE 0x1C01000
+
+#define QDSS_APB_DEC_CSR_ETRIRQCTRL_OFFSET 0x6C
+#define QDSS_APB_DEC_CSR_PRESERVEETF_OFFSET 0x70
+#define QDSS_APB_DEC_CSR_PRESERVEETR0_OFFSET 0x74
+#define QDSS_APB_DEC_CSR_PRESERVEETR1_OFFSET 0x78
+
+#define MAX_UNWINDOWED_ADDRESS 0x80000
+#define WINDOW_ENABLE_BIT 0x40000000
+#define WINDOW_SHIFT 19
+#define WINDOW_VALUE_MASK 0x3F
+#define WINDOW_START MAX_UNWINDOWED_ADDRESS
+#define WINDOW_RANGE_MASK 0x7FFFF
+
+#define QCA6390_TIME_SYNC_ENABLE 0x80000000
+#define QCA6390_TIME_SYNC_CLEAR 0x0
+
+#define QCA6390_PCIE_SOC_WDOG_DISC_BAD_DATA_LOW_CFG_SOC_PCIE_REG 0x01E04234
+#define QCA6390_PCIE_SOC_WDOG_DISC_BAD_DATA_LOW_CFG_SOC_PCIE_REG_VAL 0xDEAD1234
+#define QCA6390_PCIE_PCIE_WCSS_STATUS_FOR_DEBUG_LOW_PCIE_LOCAL_REG 0x01E03140
+#define QCA6390_PCIE_SOC_PCIE_WRAP_INTR_MASK_SOC_PCIE_REG 0x1E04054
+#define QCA6390_PCIE_SOC_PCIE_WRAP_INTR_STATUS_SOC_PCIE_REG 0x1E04058
+#define QCA6390_PCIE_SOC_COMMIT_REPLAY_SOC_PCIE_REG 0x1E05090
+#define QCA6390_PCIE_PCIE_PARF_LTSSM 0x01E081B0
+#define QCA6390_PCIE_PCIE_PARF_PM_STTS 0x01E08024
+#define QCA6390_PCIE_PCIE_PARF_PM_STTS_1 0x01E08028
+#define QCA6390_PCIE_PCIE_PARF_INT_STATUS 0x01E08220
+#define QCA6390_PCIE_PCIE_INT_ALL_STATUS 0x01E08224
+#define QCA6390_PCIE_PCIE_INT_ALL_MASK 0x01E0822C
+#define QCA6390_PCIE_PCIE_PARF_BDF_TO_SID_CFG 0x01E0AC00
+#define QCA6390_PCIE_PCIE_PARF_L1SS_SLEEP_NO_MHI_ACCESS_HANDLER_RD_4 0x01E08530
+#define QCA6390_PCIE_PCIE_PARF_L1SS_SLEEP_NO_MHI_ACCESS_HANDLER_RD_3 0x01E0852c
+#define QCA6390_PCIE_PCIE_PARF_MHI_CLOCK_RESET_CTRL 0x01E08174
+#define QCA6390_PCIE_PCIE_PARF_MHI_BASE_ADDR_LOWER 0x01E08178
+#define QCA6390_PCIE_PCIE_PARF_L1SS_SLEEP_MODE_HANDLER_STATUS 0x01E084D0
+#define QCA6390_PCIE_PCIE_PARF_L1SS_SLEEP_MODE_HANDLER_CFG 0x01E084d4
+#define QCA6390_PCIE_PCIE_PARF_DEBUG_CNT_AUX_CLK_IN_L1SUB_L2 0x01E0ec88
+#define QCA6390_PCIE_PCIE_PARF_DEBUG_CNT_PM_LINKST_IN_L1SUB 0x01E0ec08
+#define QCA6390_PCIE_PCIE_CORE_CONFIG 0x01E08640
+#define QCA6390_PCIE_PCIE_PARF_DEBUG_CNT_PM_LINKST_IN_L2 0x01E0EC04
+#define QCA6390_PCIE_PCIE_PARF_DEBUG_CNT_PM_LINKST_IN_L1 0x01E0EC0C
+#define QCA6390_PCIE_PCIE_PARF_DEBUG_CNT_AUX_CLK_IN_L1SUB_L1 0x01E0EC84
+#define QCA6390_PCIE_PCIE_LOCAL_REG_WCSSAON_PCIE_SR_STATUS_HIGH 0x01E030C8
+#define QCA6390_PCIE_PCIE_LOCAL_REG_WCSSAON_PCIE_SR_STATUS_LOW 0x01E030CC
+#define QCA6390_PCIE_PCIE_LOCAL_REG_WCSS_STATUS_FOR_DEBUG_HIGH 0x01E0313C
+#define QCA6390_PCIE_PCIE_LOCAL_REG_WCSS_STATUS_FOR_DEBUG_LOW 0x01E03140
+
+#define QCA6390_GCC_DEBUG_CLK_CTL 0x001E4025C
+
+#define QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_PLL_MODE 0x00D00200
+#define QCA6390_WCSS_WFSS_PMM_WFSS_PMM_R0_PMM_CTRL 0x00B60164
+#define QCA6390_WCSS_PMM_TOP_PMU_CX_CSR 0x00B70080
+#define QCA6390_WCSS_PMM_TOP_AON_INT_RAW_STAT 0x00B700E0
+#define QCA6390_WCSS_PMM_TOP_AON_INT_EN 0x00B700D0
+#define QCA6390_WCSS_PMM_TOP_PMU_TESTBUS_STS 0x00B70020
+#define QCA6390_WCSS_PMM_TOP_PMU_TESTBUS_CTL 0x00B7001C
+#define QCA6390_WCSS_PMM_TOP_TESTBUS_STS 0x00B70028
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_CFG 0x00DB0008
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_CFG_MSK 0x20
+#define QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_CTL 0x00D02000
+#define QCA6390_WCSS_Q6SS_PUBCSR_QDSP6SS_TEST_BUS_VALUE 0x00D02004
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_SPM_STS 0x00DB000C
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_SPM_CTL 0x00DB0030
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_SPM_SLP_SEQ_ENTRY_0 0x00DB0400
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_SAW2_SPM_SLP_SEQ_ENTRY_9 0x00DB0424
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS0 0x00D90380
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS1 0x00D90384
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS2 0x00D90388
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS3 0x00D9038C
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS4 0x00D90390
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS5 0x00D90394
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_STATUS6 0x00D90398
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE0 0x00D90100
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE1 0x00D90104
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE2 0x00D90108
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE3 0x00D9010C
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE4 0x00D90110
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE5 0x00D90114
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_ENABLE6 0x00D90118
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING0 0x00D90500
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING1 0x00D90504
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING2 0x00D90508
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING3 0x00D9050C
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING4 0x00D90510
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING5 0x00D90514
+#define QCA6390_WCSS_Q6SS_PRIVCSR_QDSP6SS_L2VIC_INT_PENDING6 0x00D90518
+#define QCA6390_WCSS_CC_WCSS_UMAC_NOC_CBCR 0x00C3029C
+#define QCA6390_WCSS_CC_WCSS_UMAC_AHB_CBCR 0x00C302BC
+#define QCA6390_WCSS_CC_WCSS_UMAC_GDSCR 0x00C30298
+#define QCA6390_WCSS_CC_WCSS_WLAN1_GDSCR 0x00C300C4
+#define QCA6390_WCSS_CC_WCSS_WLAN2_GDSCR 0x00C30138
+#define QCA6390_WCSS_PMM_TOP_PMM_INT_CLR 0x00B70168
+#define QCA6390_WCSS_PMM_TOP_AON_INT_STICKY_EN 0x00B700D8
+
+#define QCA6390_TLMM_GPIO_IN_OUT57 0x01839004
+#define QCA6390_TLMM_GPIO_INTR_CFG57 0x01839008
+#define QCA6390_TLMM_GPIO_INTR_STATUS57 0x0183900C
+#define QCA6390_TLMM_GPIO_IN_OUT59 0x0183b004
+#define QCA6390_TLMM_GPIO_INTR_CFG59 0x0183b008
+#define QCA6390_TLMM_GPIO_INTR_STATUS59 0x0183b00C
+
+#define QCA6390_WFSS_PMM_WFSS_PMM_R0_WLAN1_STATUS_REG2 0x00B6017C
+#define QCA6390_WFSS_PMM_WFSS_PMM_R0_WLAN2_STATUS_REG2 0x00B60190
+#define QCA6390_WFSS_PMM_WFSS_PMM_R0_PMM_WLAN2_CFG_REG1 0x00B6018C
+#define QCA6390_WFSS_PMM_WFSS_PMM_R0_PMM_WLAN1_CFG_REG1 0x00B60178
+#define QCA6390_WFSS_PMM_WFSS_PMM_R0_WLAN2_APS_STATUS_REG1 0x00B600B0
+#define QCA6390_WFSS_PMM_WFSS_PMM_R0_WLAN1_APS_STATUS_REG1 0x00B60044
+
+#define QCA6390_WLAON_WCSSAON_PCIE_SR_STATUS_HI_REG 0x01F806C4
+#define QCA6390_WLAON_SOC_POWER_CTRL 0x01F80000
+#define QCA6390_WLAON_PCIE_PWR_CTRL_REG 0x01F806BC
+#define QCA6390_WLAON_WCSSAON_PCIE_SR_STATUS_LO_REG 0x1F806C8
+#define QCA6390_WLAON_WCSS_TCSR_PMM_SR_STATUS_HI_REG 0x1F806CC
+#define QCA6390_WLAON_WCSS_TCSR_PMM_SR_STATUS_LO_REG 0x1F806D0
+#define QCA6390_WLAON_SOC_PWR_WDG_BARK_THRSHD 0x1F80004
+#define QCA6390_WLAON_SOC_PWR_WDG_BITE_THRSHD 0x1F80008
+#define QCA6390_WLAON_SW_COLD_RESET 0x1F8000C
+#define QCA6390_WLAON_RFA_MEM_SLP_NRET_N_OVERRIDE 0x1F8001C
+#define QCA6390_WLAON_GDSC_DELAY_SETTING 0x1F80024
+#define QCA6390_WLAON_GDSC_DELAY_SETTING2 0x1F80028
+#define QCA6390_WLAON_WL_PWR_STATUS_REG 0x1F8002C
+#define QCA6390_WLAON_WL_AON_DBG_CFG_REG 0x1F80030
+#define QCA6390_WLAON_GLOBAL_COUNTER_CTRL1 0x1F80100
+#define QCA6390_WLAON_GLOBAL_COUNTER_CTRL6 0x1F80108
+#define QCA6390_WLAON_GLOBAL_COUNTER_CTRL7 0x1F8010C
+#define QCA6390_WLAON_GLOBAL_COUNTER_CTRL3 0x1F80118
+#define QCA6390_WLAON_GLOBAL_COUNTER_CTRL4 0x1F8011C
+#define QCA6390_WLAON_GLOBAL_COUNTER_CTRL5 0x1F80120
+#define QCA6390_WLAON_GLOBAL_COUNTER_CTRL8 0x1F801F0
+#define QCA6390_WLAON_GLOBAL_COUNTER_CTRL2 0x1F801F4
+#define QCA6390_WLAON_GLOBAL_COUNTER_CTRL9 0x1F801F8
+#define QCA6390_WLAON_RTC_CLK_CAL_CTRL1 0x1F80200
+#define QCA6390_WLAON_RTC_CLK_CAL_CTRL2 0x1F80204
+#define QCA6390_WLAON_RTC_CLK_CAL_CTRL3 0x1F80208
+#define QCA6390_WLAON_RTC_CLK_CAL_CTRL4 0x1F8020C
+#define QCA6390_WLAON_RTC_CLK_CAL_CTRL5 0x1F80210
+#define QCA6390_WLAON_RTC_CLK_CAL_CTRL6 0x1F80214
+#define QCA6390_WLAON_RTC_CLK_CAL_CTRL7 0x1F80218
+#define QCA6390_WLAON_RTC_CLK_CAL_CTRL8 0x1F8021C
+#define QCA6390_WLAON_RTC_CLK_CAL_CTRL9 0x1F80220
+#define QCA6390_WLAON_WCSSAON_CONFIG_REG 0x1F80300
+#define QCA6390_WLAON_WLAN_OEM_DEBUG_REG 0x1F80304
+#define QCA6390_WLAON_WLAN_RAM_DUMP_REG 0x1F80308
+#define QCA6390_WLAON_QDSS_WCSS_REG 0x1F8030C
+#define QCA6390_WLAON_QDSS_WCSS_ACK 0x1F80310
+#define QCA6390_WLAON_WL_CLK_CNTL_KDF_REG 0x1F80314
+#define QCA6390_WLAON_WL_CLK_CNTL_PMU_HFRC_REG 0x1F80318
+#define QCA6390_WLAON_QFPROM_PWR_CTRL_REG 0x1F8031C
+#define QCA6390_WLAON_DLY_CONFIG 0x1F80400
+#define QCA6390_WLAON_WLAON_Q6_IRQ_REG 0x1F80404
+#define QCA6390_WLAON_PCIE_INTF_SW_CFG_REG 0x1F80408
+#define QCA6390_WLAON_PCIE_INTF_STICKY_SW_CFG_REG 0x1F8040C
+#define QCA6390_WLAON_PCIE_INTF_PHY_SW_CFG_REG 0x1F80410
+#define QCA6390_WLAON_PCIE_INTF_PHY_NOCSR_SW_CFG_REG 0x1F80414
+#define QCA6390_WLAON_Q6_COOKIE_BIT 0x1F80500
+#define QCA6390_WLAON_WARM_SW_ENTRY 0x1F80504
+#define QCA6390_WLAON_RESET_DBG_SW_ENTRY 0x1F80508
+#define QCA6390_WLAON_WL_PMUNOC_CFG_REG 0x1F8050C
+#define QCA6390_WLAON_RESET_CAUSE_CFG_REG 0x1F80510
+#define QCA6390_WLAON_SOC_WCSSAON_WAKEUP_IRQ_7_EN_REG 0x1F80514
+#define QCA6390_WLAON_DEBUG 0x1F80600
+#define QCA6390_WLAON_SOC_PARAMETERS 0x1F80604
+#define QCA6390_WLAON_WLPM_SIGNAL 0x1F80608
+#define QCA6390_WLAON_SOC_RESET_CAUSE_REG 0x1F8060C
+#define QCA6390_WLAON_WAKEUP_PCIE_SOC_REG 0x1F80610
+#define QCA6390_WLAON_PBL_STACK_CANARY 0x1F80614
+#define QCA6390_WLAON_MEM_TOT_NUM_GRP_REG 0x1F80618
+#define QCA6390_WLAON_MEM_TOT_BANKS_IN_GRP0_REG 0x1F8061C
+#define QCA6390_WLAON_MEM_TOT_BANKS_IN_GRP1_REG 0x1F80620
+#define QCA6390_WLAON_MEM_TOT_BANKS_IN_GRP2_REG 0x1F80624
+#define QCA6390_WLAON_MEM_TOT_BANKS_IN_GRP3_REG 0x1F80628
+#define QCA6390_WLAON_MEM_TOT_SIZE_IN_GRP0_REG 0x1F8062C
+#define QCA6390_WLAON_MEM_TOT_SIZE_IN_GRP1_REG 0x1F80630
+#define QCA6390_WLAON_MEM_TOT_SIZE_IN_GRP2_REG 0x1F80634
+#define QCA6390_WLAON_MEM_TOT_SIZE_IN_GRP3_REG 0x1F80638
+#define QCA6390_WLAON_MEM_SLP_NRET_OVERRIDE_GRP0_REG 0x1F8063C
+#define QCA6390_WLAON_MEM_SLP_NRET_OVERRIDE_GRP1_REG 0x1F80640
+#define QCA6390_WLAON_MEM_SLP_NRET_OVERRIDE_GRP2_REG 0x1F80644
+#define QCA6390_WLAON_MEM_SLP_NRET_OVERRIDE_GRP3_REG 0x1F80648
+#define QCA6390_WLAON_MEM_SLP_RET_OVERRIDE_GRP0_REG 0x1F8064C
+#define QCA6390_WLAON_MEM_SLP_RET_OVERRIDE_GRP1_REG 0x1F80650
+#define QCA6390_WLAON_MEM_SLP_RET_OVERRIDE_GRP2_REG 0x1F80654
+#define QCA6390_WLAON_MEM_SLP_RET_OVERRIDE_GRP3_REG 0x1F80658
+#define QCA6390_WLAON_MEM_CNT_SEL_REG 0x1F8065C
+#define QCA6390_WLAON_MEM_NO_EXTBHS_REG 0x1F80660
+#define QCA6390_WLAON_MEM_DEBUG_REG 0x1F80664
+#define QCA6390_WLAON_MEM_DEBUG_BUS_REG 0x1F80668
+#define QCA6390_WLAON_MEM_REDUN_CFG_REG 0x1F8066C
+#define QCA6390_WLAON_WL_AON_SPARE2 0x1F80670
+#define QCA6390_WLAON_VSEL_CFG_FOR_WL_RET_DISABLE_REG 0x1F80680
+#define QCA6390_WLAON_BTFM_WLAN_IPC_STATUS_REG 0x1F80690
+#define QCA6390_WLAON_MPM_COUNTER_CHICKEN_BITS 0x1F806A0
+#define QCA6390_WLAON_WLPM_CHICKEN_BITS 0x1F806A4
+#define QCA6390_WLAON_PCIE_PHY_PWR_REG 0x1F806A8
+#define QCA6390_WLAON_WL_CLK_CNTL_PMU_LPO2M_REG 0x1F806AC
+#define QCA6390_WLAON_WL_SS_ROOT_CLK_SWITCH_REG 0x1F806B0
+#define QCA6390_WLAON_POWERCTRL_PMU_REG 0x1F806B4
+#define QCA6390_WLAON_POWERCTRL_MEM_REG 0x1F806B8
+#define QCA6390_WLAON_SOC_PWR_PROFILE_REG 0x1F806C0
+#define QCA6390_WLAON_MEM_SVS_CFG_REG 0x1F806D4
+#define QCA6390_WLAON_CMN_AON_MISC_REG 0x1F806D8
+#define QCA6390_WLAON_INTR_STATUS 0x1F80700
+
+#define QCA6390_SYSPM_SYSPM_PWR_STATUS 0x1F82000
+#define QCA6390_SYSPM_DBG_BTFM_AON_REG 0x1F82004
+#define QCA6390_SYSPM_DBG_BUS_SEL_REG 0x1F82008
+#define QCA6390_SYSPM_WCSSAON_SR_STATUS 0x1F8200C
+
+#endif
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/smem.c b/drivers/net/wireless/intel/iwlwifi/fw/smem.c
index ff85d69..557ee47 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/smem.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/smem.c
@@ -8,7 +8,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
- * Copyright(c) 2018 Intel Corporation
+ * Copyright(c) 2018 - 2019 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -31,7 +31,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
- * Copyright(c) 2018 Intel Corporation
+ * Copyright(c) 2018 - 2019 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -134,6 +134,7 @@ void iwl_get_shared_mem_conf(struct iwl_fw_runtime *fwrt)
.len = { 0, },
};
struct iwl_rx_packet *pkt;
+ int ret;
if (fw_has_capa(&fwrt->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_EXTEND_SHARED_MEM_CFG))
@@ -141,8 +142,13 @@ void iwl_get_shared_mem_conf(struct iwl_fw_runtime *fwrt)
else
cmd.id = SHARED_MEM_CFG;
- if (WARN_ON(iwl_trans_send_cmd(fwrt->trans, &cmd)))
+ ret = iwl_trans_send_cmd(fwrt->trans, &cmd);
+
+ if (ret) {
+ WARN(ret != -ERFKILL,
+ "Could not send the SMEM command: %d\n", ret);
return;
+ }
pkt = cmd.resp_pkt;
if (fwrt->trans->cfg->device_family >= IWL_DEVICE_FAMILY_22000)
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
index c063125..db6628d 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
@@ -1547,7 +1547,6 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
goto free;
out_free_fw:
- iwl_dealloc_ucode(drv);
release_firmware(ucode_raw);
out_unbind:
complete(&drv->request_firmware_complete);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
index 2d21f0a..ffae299 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
@@ -641,6 +641,9 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
memcpy(&info, skb->cb, sizeof(info));
+ if (WARN_ON_ONCE(skb->len > IEEE80211_MAX_DATA_LEN + hdrlen))
+ return -1;
+
if (WARN_ON_ONCE(info.flags & IEEE80211_TX_CTL_AMPDU))
return -1;
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
index 2146fda..64d976d 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c
@@ -164,7 +164,7 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans,
memcpy(iml_img, trans->iml, trans->iml_len);
- iwl_enable_interrupts(trans);
+ iwl_enable_fw_load_int_ctx_info(trans);
/* kick FW self load */
iwl_write64(trans, CSR_CTXT_INFO_ADDR,
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c
index b2cd7ef..6f25fd1 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c
@@ -206,7 +206,7 @@ int iwl_pcie_ctxt_info_init(struct iwl_trans *trans,
trans_pcie->ctxt_info = ctxt_info;
- iwl_enable_interrupts(trans);
+ iwl_enable_fw_load_int_ctx_info(trans);
/* Configure debug, if exists */
if (trans->dbg_dest_tlv)
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
index b63d44b..00f9566 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
@@ -896,6 +896,33 @@ static inline void iwl_enable_fw_load_int(struct iwl_trans *trans)
}
}
+static inline void iwl_enable_fw_load_int_ctx_info(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+ IWL_DEBUG_ISR(trans, "Enabling ALIVE interrupt only\n");
+
+ if (!trans_pcie->msix_enabled) {
+ /*
+ * When we'll receive the ALIVE interrupt, the ISR will call
+ * iwl_enable_fw_load_int_ctx_info again to set the ALIVE
+ * interrupt (which is not really needed anymore) but also the
+ * RX interrupt which will allow us to receive the ALIVE
+ * notification (which is Rx) and continue the flow.
+ */
+ trans_pcie->inta_mask = CSR_INT_BIT_ALIVE | CSR_INT_BIT_FH_RX;
+ iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
+ } else {
+ iwl_enable_hw_int_msk_msix(trans,
+ MSIX_HW_INT_CAUSES_REG_ALIVE);
+ /*
+ * Leave all the FH causes enabled to get the ALIVE
+ * notification.
+ */
+ iwl_enable_fh_int_msk_msix(trans, trans_pcie->fh_init_mask);
+ }
+}
+
static inline u16 iwl_pcie_get_cmd_index(const struct iwl_txq *q, u32 index)
{
return index & (q->n_window - 1);
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
index 6dcd537..1d14498 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
@@ -1778,26 +1778,26 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
goto out;
}
- if (iwl_have_debug_level(IWL_DL_ISR)) {
- /* NIC fires this, but we don't use it, redundant with WAKEUP */
- if (inta & CSR_INT_BIT_SCD) {
- IWL_DEBUG_ISR(trans,
- "Scheduler finished to transmit the frame/frames.\n");
- isr_stats->sch++;
+ /* NIC fires this, but we don't use it, redundant with WAKEUP */
+ if (inta & CSR_INT_BIT_SCD) {
+ IWL_DEBUG_ISR(trans,
+ "Scheduler finished to transmit the frame/frames.\n");
+ isr_stats->sch++;
+ }
+
+ /* Alive notification via Rx interrupt will do the real work */
+ if (inta & CSR_INT_BIT_ALIVE) {
+ IWL_DEBUG_ISR(trans, "Alive interrupt\n");
+ isr_stats->alive++;
+ if (trans->cfg->gen2) {
+ /*
+ * We can restock, since firmware configured
+ * the RFH
+ */
+ iwl_pcie_rxmq_restock(trans, trans_pcie->rxq);
}
- /* Alive notification via Rx interrupt will do the real work */
- if (inta & CSR_INT_BIT_ALIVE) {
- IWL_DEBUG_ISR(trans, "Alive interrupt\n");
- isr_stats->alive++;
- if (trans->cfg->gen2) {
- /*
- * We can restock, since firmware configured
- * the RFH
- */
- iwl_pcie_rxmq_restock(trans, trans_pcie->rxq);
- }
- }
+ handled |= CSR_INT_BIT_ALIVE;
}
/* Safely ignore these bits for debug checks below */
@@ -1916,6 +1916,9 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
/* Re-enable RF_KILL if it occurred */
else if (handled & CSR_INT_BIT_RF_KILL)
iwl_enable_rfkill_int(trans);
+ /* Re-enable the ALIVE / Rx interrupt if it occurred */
+ else if (handled & (CSR_INT_BIT_ALIVE | CSR_INT_BIT_FH_RX))
+ iwl_enable_fw_load_int_ctx_info(trans);
spin_unlock(&trans_pcie->irq_lock);
out:
@@ -2060,10 +2063,18 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id)
return IRQ_NONE;
}
- if (iwl_have_debug_level(IWL_DL_ISR))
- IWL_DEBUG_ISR(trans, "ISR inta_fh 0x%08x, enabled 0x%08x\n",
- inta_fh,
+ if (iwl_have_debug_level(IWL_DL_ISR)) {
+ IWL_DEBUG_ISR(trans,
+ "ISR inta_fh 0x%08x, enabled (sw) 0x%08x (hw) 0x%08x\n",
+ inta_fh, trans_pcie->fh_mask,
iwl_read32(trans, CSR_MSIX_FH_INT_MASK_AD));
+ if (inta_fh & ~trans_pcie->fh_mask)
+ IWL_DEBUG_ISR(trans,
+ "We got a masked interrupt (0x%08x)\n",
+ inta_fh & ~trans_pcie->fh_mask);
+ }
+
+ inta_fh &= trans_pcie->fh_mask;
if ((trans_pcie->shared_vec_mask & IWL_SHARED_IRQ_NON_RX) &&
inta_fh & MSIX_FH_INT_CAUSES_Q0) {
@@ -2103,11 +2114,18 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id)
}
/* After checking FH register check HW register */
- if (iwl_have_debug_level(IWL_DL_ISR))
+ if (iwl_have_debug_level(IWL_DL_ISR)) {
IWL_DEBUG_ISR(trans,
- "ISR inta_hw 0x%08x, enabled 0x%08x\n",
- inta_hw,
+ "ISR inta_hw 0x%08x, enabled (sw) 0x%08x (hw) 0x%08x\n",
+ inta_hw, trans_pcie->hw_mask,
iwl_read32(trans, CSR_MSIX_HW_INT_MASK_AD));
+ if (inta_hw & ~trans_pcie->hw_mask)
+ IWL_DEBUG_ISR(trans,
+ "We got a masked interrupt 0x%08x\n",
+ inta_hw & ~trans_pcie->hw_mask);
+ }
+
+ inta_hw &= trans_pcie->hw_mask;
/* Alive notification via Rx interrupt will do the real work */
if (inta_hw & MSIX_HW_INT_CAUSES_REG_ALIVE) {
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c
index 2bc6721..31e72e1 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c
@@ -289,6 +289,15 @@ void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans, u32 scd_addr)
* paging memory cannot be freed included since FW will still use it
*/
iwl_pcie_ctxt_info_free(trans);
+
+ /*
+ * Re-enable all the interrupts, including the RF-Kill one, now that
+ * the firmware is alive.
+ */
+ iwl_enable_interrupts(trans);
+ mutex_lock(&trans_pcie->mutex);
+ iwl_pcie_check_hw_rf_kill(trans);
+ mutex_unlock(&trans_pcie->mutex);
}
int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans,
diff --git a/drivers/net/wireless/intersil/p54/p54usb.c b/drivers/net/wireless/intersil/p54/p54usb.c
index b0b86f7..15661da 100644
--- a/drivers/net/wireless/intersil/p54/p54usb.c
+++ b/drivers/net/wireless/intersil/p54/p54usb.c
@@ -33,6 +33,8 @@ MODULE_ALIAS("prism54usb");
MODULE_FIRMWARE("isl3886usb");
MODULE_FIRMWARE("isl3887usb");
+static struct usb_driver p54u_driver;
+
/*
* Note:
*
@@ -921,9 +923,9 @@ static void p54u_load_firmware_cb(const struct firmware *firmware,
{
struct p54u_priv *priv = context;
struct usb_device *udev = priv->udev;
+ struct usb_interface *intf = priv->intf;
int err;
- complete(&priv->fw_wait_load);
if (firmware) {
priv->fw = firmware;
err = p54u_start_ops(priv);
@@ -932,26 +934,22 @@ static void p54u_load_firmware_cb(const struct firmware *firmware,
dev_err(&udev->dev, "Firmware not found.\n");
}
+ complete(&priv->fw_wait_load);
+ /*
+ * At this point p54u_disconnect may have already freed
+ * the "priv" context. Do not use it anymore!
+ */
+ priv = NULL;
+
if (err) {
- struct device *parent = priv->udev->dev.parent;
+ dev_err(&intf->dev, "failed to initialize device (%d)\n", err);
- dev_err(&udev->dev, "failed to initialize device (%d)\n", err);
-
- if (parent)
- device_lock(parent);
-
- device_release_driver(&udev->dev);
- /*
- * At this point p54u_disconnect has already freed
- * the "priv" context. Do not use it anymore!
- */
- priv = NULL;
-
- if (parent)
- device_unlock(parent);
+ usb_lock_device(udev);
+ usb_driver_release_interface(&p54u_driver, intf);
+ usb_unlock_device(udev);
}
- usb_put_dev(udev);
+ usb_put_intf(intf);
}
static int p54u_load_firmware(struct ieee80211_hw *dev,
@@ -972,14 +970,14 @@ static int p54u_load_firmware(struct ieee80211_hw *dev,
dev_info(&priv->udev->dev, "Loading firmware file %s\n",
p54u_fwlist[i].fw);
- usb_get_dev(udev);
+ usb_get_intf(intf);
err = request_firmware_nowait(THIS_MODULE, 1, p54u_fwlist[i].fw,
device, GFP_KERNEL, priv,
p54u_load_firmware_cb);
if (err) {
dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
"(%d)!\n", p54u_fwlist[i].fw, err);
- usb_put_dev(udev);
+ usb_put_intf(intf);
}
return err;
@@ -1011,8 +1009,6 @@ static int p54u_probe(struct usb_interface *intf,
skb_queue_head_init(&priv->rx_queue);
init_usb_anchor(&priv->submitted);
- usb_get_dev(udev);
-
/* really lazy and simple way of figuring out if we're a 3887 */
/* TODO: should just stick the identification in the device table */
i = intf->altsetting->desc.bNumEndpoints;
@@ -1053,10 +1049,8 @@ static int p54u_probe(struct usb_interface *intf,
priv->upload_fw = p54u_upload_firmware_net2280;
}
err = p54u_load_firmware(dev, intf);
- if (err) {
- usb_put_dev(udev);
+ if (err)
p54_free_common(dev);
- }
return err;
}
@@ -1072,7 +1066,6 @@ static void p54u_disconnect(struct usb_interface *intf)
wait_for_completion(&priv->fw_wait_load);
p54_unregister_common(dev);
- usb_put_dev(interface_to_usbdev(intf));
release_firmware(priv->fw);
p54_free_common(dev);
}
diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h
index b73f99d..1fb76d2 100644
--- a/drivers/net/wireless/marvell/mwifiex/fw.h
+++ b/drivers/net/wireless/marvell/mwifiex/fw.h
@@ -1759,9 +1759,10 @@ struct mwifiex_ie_types_wmm_queue_status {
struct ieee_types_vendor_header {
u8 element_id;
u8 len;
- u8 oui[4]; /* 0~2: oui, 3: oui_type */
- u8 oui_subtype;
- u8 version;
+ struct {
+ u8 oui[3];
+ u8 oui_type;
+ } __packed oui;
} __packed;
struct ieee_types_wmm_parameter {
@@ -1775,6 +1776,9 @@ struct ieee_types_wmm_parameter {
* Version [1]
*/
struct ieee_types_vendor_header vend_hdr;
+ u8 oui_subtype;
+ u8 version;
+
u8 qos_info_bitmap;
u8 reserved;
struct ieee_types_wmm_ac_parameters ac_params[IEEE80211_NUM_ACS];
@@ -1792,6 +1796,8 @@ struct ieee_types_wmm_info {
* Version [1]
*/
struct ieee_types_vendor_header vend_hdr;
+ u8 oui_subtype;
+ u8 version;
u8 qos_info_bitmap;
} __packed;
diff --git a/drivers/net/wireless/marvell/mwifiex/ie.c b/drivers/net/wireless/marvell/mwifiex/ie.c
index 75cbd60..801a2d7 100644
--- a/drivers/net/wireless/marvell/mwifiex/ie.c
+++ b/drivers/net/wireless/marvell/mwifiex/ie.c
@@ -329,6 +329,8 @@ static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv,
struct ieee80211_vendor_ie *vendorhdr;
u16 gen_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0;
int left_len, parsed_len = 0;
+ unsigned int token_len;
+ int err = 0;
if (!info->tail || !info->tail_len)
return 0;
@@ -344,6 +346,12 @@ static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv,
*/
while (left_len > sizeof(struct ieee_types_header)) {
hdr = (void *)(info->tail + parsed_len);
+ token_len = hdr->len + sizeof(struct ieee_types_header);
+ if (token_len > left_len) {
+ err = -EINVAL;
+ goto out;
+ }
+
switch (hdr->element_id) {
case WLAN_EID_SSID:
case WLAN_EID_SUPP_RATES:
@@ -361,16 +369,19 @@ static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv,
if (cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
WLAN_OUI_TYPE_MICROSOFT_WMM,
(const u8 *)hdr,
- hdr->len + sizeof(struct ieee_types_header)))
+ token_len))
break;
default:
- memcpy(gen_ie->ie_buffer + ie_len, hdr,
- hdr->len + sizeof(struct ieee_types_header));
- ie_len += hdr->len + sizeof(struct ieee_types_header);
+ if (ie_len + token_len > IEEE_MAX_IE_SIZE) {
+ err = -EINVAL;
+ goto out;
+ }
+ memcpy(gen_ie->ie_buffer + ie_len, hdr, token_len);
+ ie_len += token_len;
break;
}
- left_len -= hdr->len + sizeof(struct ieee_types_header);
- parsed_len += hdr->len + sizeof(struct ieee_types_header);
+ left_len -= token_len;
+ parsed_len += token_len;
}
/* parse only WPA vendor IE from tail, WMM IE is configured by
@@ -380,15 +391,17 @@ static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv,
WLAN_OUI_TYPE_MICROSOFT_WPA,
info->tail, info->tail_len);
if (vendorhdr) {
- memcpy(gen_ie->ie_buffer + ie_len, vendorhdr,
- vendorhdr->len + sizeof(struct ieee_types_header));
- ie_len += vendorhdr->len + sizeof(struct ieee_types_header);
+ token_len = vendorhdr->len + sizeof(struct ieee_types_header);
+ if (ie_len + token_len > IEEE_MAX_IE_SIZE) {
+ err = -EINVAL;
+ goto out;
+ }
+ memcpy(gen_ie->ie_buffer + ie_len, vendorhdr, token_len);
+ ie_len += token_len;
}
- if (!ie_len) {
- kfree(gen_ie);
- return 0;
- }
+ if (!ie_len)
+ goto out;
gen_ie->ie_index = cpu_to_le16(gen_idx);
gen_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON |
@@ -398,13 +411,15 @@ static int mwifiex_uap_parse_tail_ies(struct mwifiex_private *priv,
if (mwifiex_update_uap_custom_ie(priv, gen_ie, &gen_idx, NULL, NULL,
NULL, NULL)) {
- kfree(gen_ie);
- return -1;
+ err = -EINVAL;
+ goto out;
}
priv->gen_idx = gen_idx;
+
+ out:
kfree(gen_ie);
- return 0;
+ return err;
}
/* This function parses different IEs-head & tail IEs, beacon IEs,
diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c
index 8e483b0..6dd771c 100644
--- a/drivers/net/wireless/marvell/mwifiex/scan.c
+++ b/drivers/net/wireless/marvell/mwifiex/scan.c
@@ -1247,6 +1247,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
}
switch (element_id) {
case WLAN_EID_SSID:
+ if (element_len > IEEE80211_MAX_SSID_LEN)
+ return -EINVAL;
bss_entry->ssid.ssid_len = element_len;
memcpy(bss_entry->ssid.ssid, (current_ptr + 2),
element_len);
@@ -1256,6 +1258,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
break;
case WLAN_EID_SUPP_RATES:
+ if (element_len > MWIFIEX_SUPPORTED_RATES)
+ return -EINVAL;
memcpy(bss_entry->data_rates, current_ptr + 2,
element_len);
memcpy(bss_entry->supported_rates, current_ptr + 2,
@@ -1265,6 +1269,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
break;
case WLAN_EID_FH_PARAMS:
+ if (element_len + 2 < sizeof(*fh_param_set))
+ return -EINVAL;
fh_param_set =
(struct ieee_types_fh_param_set *) current_ptr;
memcpy(&bss_entry->phy_param_set.fh_param_set,
@@ -1273,6 +1279,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
break;
case WLAN_EID_DS_PARAMS:
+ if (element_len + 2 < sizeof(*ds_param_set))
+ return -EINVAL;
ds_param_set =
(struct ieee_types_ds_param_set *) current_ptr;
@@ -1284,6 +1292,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
break;
case WLAN_EID_CF_PARAMS:
+ if (element_len + 2 < sizeof(*cf_param_set))
+ return -EINVAL;
cf_param_set =
(struct ieee_types_cf_param_set *) current_ptr;
memcpy(&bss_entry->ss_param_set.cf_param_set,
@@ -1292,6 +1302,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
break;
case WLAN_EID_IBSS_PARAMS:
+ if (element_len + 2 < sizeof(*ibss_param_set))
+ return -EINVAL;
ibss_param_set =
(struct ieee_types_ibss_param_set *)
current_ptr;
@@ -1301,10 +1313,14 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
break;
case WLAN_EID_ERP_INFO:
+ if (!element_len)
+ return -EINVAL;
bss_entry->erp_flags = *(current_ptr + 2);
break;
case WLAN_EID_PWR_CONSTRAINT:
+ if (!element_len)
+ return -EINVAL;
bss_entry->local_constraint = *(current_ptr + 2);
bss_entry->sensed_11h = true;
break;
@@ -1348,15 +1364,22 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
vendor_ie = (struct ieee_types_vendor_specific *)
current_ptr;
- if (!memcmp
- (vendor_ie->vend_hdr.oui, wpa_oui,
- sizeof(wpa_oui))) {
+ /* 802.11 requires at least 3-byte OUI. */
+ if (element_len < sizeof(vendor_ie->vend_hdr.oui.oui))
+ return -EINVAL;
+
+ /* Not long enough for a match? Skip it. */
+ if (element_len < sizeof(wpa_oui))
+ break;
+
+ if (!memcmp(&vendor_ie->vend_hdr.oui, wpa_oui,
+ sizeof(wpa_oui))) {
bss_entry->bcn_wpa_ie =
(struct ieee_types_vendor_specific *)
current_ptr;
bss_entry->wpa_offset = (u16)
(current_ptr - bss_entry->beacon_buf);
- } else if (!memcmp(vendor_ie->vend_hdr.oui, wmm_oui,
+ } else if (!memcmp(&vendor_ie->vend_hdr.oui, wmm_oui,
sizeof(wmm_oui))) {
if (total_ie_len ==
sizeof(struct ieee_types_wmm_parameter) ||
diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c
index b454b5f..843d65b 100644
--- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c
@@ -1348,7 +1348,7 @@ mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr,
/* Test to see if it is a WPA IE, if not, then
* it is a gen IE
*/
- if (!memcmp(pvendor_ie->oui, wpa_oui,
+ if (!memcmp(&pvendor_ie->oui, wpa_oui,
sizeof(wpa_oui))) {
/* IE is a WPA/WPA2 IE so call set_wpa function
*/
@@ -1358,7 +1358,7 @@ mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr,
goto next_ie;
}
- if (!memcmp(pvendor_ie->oui, wps_oui,
+ if (!memcmp(&pvendor_ie->oui, wps_oui,
sizeof(wps_oui))) {
/* Test to see if it is a WPS IE,
* if so, enable wps session flag
diff --git a/drivers/net/wireless/marvell/mwifiex/wmm.c b/drivers/net/wireless/marvell/mwifiex/wmm.c
index 407b9932..64916ba 100644
--- a/drivers/net/wireless/marvell/mwifiex/wmm.c
+++ b/drivers/net/wireless/marvell/mwifiex/wmm.c
@@ -240,7 +240,7 @@ mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv,
mwifiex_dbg(priv->adapter, INFO,
"info: WMM Parameter IE: version=%d,\t"
"qos_info Parameter Set Count=%d, Reserved=%#x\n",
- wmm_ie->vend_hdr.version, wmm_ie->qos_info_bitmap &
+ wmm_ie->version, wmm_ie->qos_info_bitmap &
IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK,
wmm_ie->reserved);
diff --git a/drivers/net/wireless/mediatek/mt7601u/dma.c b/drivers/net/wireless/mediatek/mt7601u/dma.c
index 7f3e398..47cebb2 100644
--- a/drivers/net/wireless/mediatek/mt7601u/dma.c
+++ b/drivers/net/wireless/mediatek/mt7601u/dma.c
@@ -193,10 +193,23 @@ static void mt7601u_complete_rx(struct urb *urb)
struct mt7601u_rx_queue *q = &dev->rx_q;
unsigned long flags;
- spin_lock_irqsave(&dev->rx_lock, flags);
+ /* do no schedule rx tasklet if urb has been unlinked
+ * or the device has been removed
+ */
+ switch (urb->status) {
+ case -ECONNRESET:
+ case -ESHUTDOWN:
+ case -ENOENT:
+ return;
+ default:
+ dev_err_ratelimited(dev->dev, "rx urb failed: %d\n",
+ urb->status);
+ /* fall through */
+ case 0:
+ break;
+ }
- if (mt7601u_urb_has_error(urb))
- dev_err(dev->dev, "Error: RX urb failed:%d\n", urb->status);
+ spin_lock_irqsave(&dev->rx_lock, flags);
if (WARN_ONCE(q->e[q->end].urb != urb, "RX urb mismatch"))
goto out;
@@ -228,14 +241,25 @@ static void mt7601u_complete_tx(struct urb *urb)
struct sk_buff *skb;
unsigned long flags;
- spin_lock_irqsave(&dev->tx_lock, flags);
+ switch (urb->status) {
+ case -ECONNRESET:
+ case -ESHUTDOWN:
+ case -ENOENT:
+ return;
+ default:
+ dev_err_ratelimited(dev->dev, "tx urb failed: %d\n",
+ urb->status);
+ /* fall through */
+ case 0:
+ break;
+ }
- if (mt7601u_urb_has_error(urb))
- dev_err(dev->dev, "Error: TX urb failed:%d\n", urb->status);
+ spin_lock_irqsave(&dev->tx_lock, flags);
if (WARN_ONCE(q->e[q->start].urb != urb, "TX urb mismatch"))
goto out;
skb = q->e[q->start].skb;
+ q->e[q->start].skb = NULL;
trace_mt_tx_dma_done(dev, skb);
__skb_queue_tail(&dev->tx_skb_done, skb);
@@ -363,19 +387,9 @@ int mt7601u_dma_enqueue_tx(struct mt7601u_dev *dev, struct sk_buff *skb,
static void mt7601u_kill_rx(struct mt7601u_dev *dev)
{
int i;
- unsigned long flags;
- spin_lock_irqsave(&dev->rx_lock, flags);
-
- for (i = 0; i < dev->rx_q.entries; i++) {
- int next = dev->rx_q.end;
-
- spin_unlock_irqrestore(&dev->rx_lock, flags);
- usb_poison_urb(dev->rx_q.e[next].urb);
- spin_lock_irqsave(&dev->rx_lock, flags);
- }
-
- spin_unlock_irqrestore(&dev->rx_lock, flags);
+ for (i = 0; i < dev->rx_q.entries; i++)
+ usb_poison_urb(dev->rx_q.e[i].urb);
}
static int mt7601u_submit_rx_buf(struct mt7601u_dev *dev,
@@ -445,10 +459,10 @@ static void mt7601u_free_tx_queue(struct mt7601u_tx_queue *q)
{
int i;
- WARN_ON(q->used);
-
for (i = 0; i < q->entries; i++) {
usb_poison_urb(q->e[i].urb);
+ if (q->e[i].skb)
+ mt7601u_tx_status(q->dev, q->e[i].skb);
usb_free_urb(q->e[i].urb);
}
}
diff --git a/drivers/net/wireless/mediatek/mt7601u/tx.c b/drivers/net/wireless/mediatek/mt7601u/tx.c
index 3600e91..4d81c45 100644
--- a/drivers/net/wireless/mediatek/mt7601u/tx.c
+++ b/drivers/net/wireless/mediatek/mt7601u/tx.c
@@ -117,9 +117,9 @@ void mt7601u_tx_status(struct mt7601u_dev *dev, struct sk_buff *skb)
info->status.rates[0].idx = -1;
info->flags |= IEEE80211_TX_STAT_ACK;
- spin_lock(&dev->mac_lock);
+ spin_lock_bh(&dev->mac_lock);
ieee80211_tx_status(dev->hw, skb);
- spin_unlock(&dev->mac_lock);
+ spin_unlock_bh(&dev->mac_lock);
}
static int mt7601u_skb_rooms(struct mt7601u_dev *dev, struct sk_buff *skb)
diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.c b/drivers/net/wireless/realtek/rtlwifi/usb.c
index 2ac5004..5adb939 100644
--- a/drivers/net/wireless/realtek/rtlwifi/usb.c
+++ b/drivers/net/wireless/realtek/rtlwifi/usb.c
@@ -1081,13 +1081,13 @@ int rtl_usb_probe(struct usb_interface *intf,
rtlpriv->cfg->ops->read_eeprom_info(hw);
err = _rtl_usb_init(hw);
if (err)
- goto error_out;
+ goto error_out2;
rtl_usb_init_sw(hw);
/* Init mac80211 sw */
err = rtl_init_core(hw);
if (err) {
pr_err("Can't allocate sw for mac80211\n");
- goto error_out;
+ goto error_out2;
}
if (rtlpriv->cfg->ops->init_sw_vars(hw)) {
pr_err("Can't init_sw_vars\n");
@@ -1108,6 +1108,7 @@ int rtl_usb_probe(struct usb_interface *intf,
error_out:
rtl_deinit_core(hw);
+error_out2:
_rtl_usb_io_handler_release(hw);
usb_put_dev(udev);
complete(&rtlpriv->firmware_loading_complete);
diff --git a/drivers/nfc/nfcmrvl/main.c b/drivers/nfc/nfcmrvl/main.c
index e65d027..529be35a 100644
--- a/drivers/nfc/nfcmrvl/main.c
+++ b/drivers/nfc/nfcmrvl/main.c
@@ -244,7 +244,7 @@ void nfcmrvl_chip_reset(struct nfcmrvl_private *priv)
/* Reset possible fault of previous session */
clear_bit(NFCMRVL_PHY_ERROR, &priv->flags);
- if (priv->config.reset_n_io) {
+ if (gpio_is_valid(priv->config.reset_n_io)) {
nfc_info(priv->dev, "reset the chip\n");
gpio_set_value(priv->config.reset_n_io, 0);
usleep_range(5000, 10000);
@@ -255,7 +255,7 @@ void nfcmrvl_chip_reset(struct nfcmrvl_private *priv)
void nfcmrvl_chip_halt(struct nfcmrvl_private *priv)
{
- if (priv->config.reset_n_io)
+ if (gpio_is_valid(priv->config.reset_n_io))
gpio_set_value(priv->config.reset_n_io, 0);
}
diff --git a/drivers/nfc/nfcmrvl/uart.c b/drivers/nfc/nfcmrvl/uart.c
index 9a22056..e5a622c 100644
--- a/drivers/nfc/nfcmrvl/uart.c
+++ b/drivers/nfc/nfcmrvl/uart.c
@@ -26,7 +26,7 @@
static unsigned int hci_muxed;
static unsigned int flow_control;
static unsigned int break_control;
-static unsigned int reset_n_io;
+static int reset_n_io = -EINVAL;
/*
** NFCMRVL NCI OPS
@@ -231,5 +231,5 @@ MODULE_PARM_DESC(break_control, "Tell if UART driver must drive break signal.");
module_param(hci_muxed, uint, 0);
MODULE_PARM_DESC(hci_muxed, "Tell if transport is muxed in HCI one.");
-module_param(reset_n_io, uint, 0);
+module_param(reset_n_io, int, 0);
MODULE_PARM_DESC(reset_n_io, "GPIO that is wired to RESET_N signal.");
diff --git a/drivers/nfc/nfcmrvl/usb.c b/drivers/nfc/nfcmrvl/usb.c
index 945cc90..888e298 100644
--- a/drivers/nfc/nfcmrvl/usb.c
+++ b/drivers/nfc/nfcmrvl/usb.c
@@ -305,6 +305,7 @@ static int nfcmrvl_probe(struct usb_interface *intf,
/* No configuration for USB */
memset(&config, 0, sizeof(config));
+ config.reset_n_io = -EINVAL;
nfc_info(&udev->dev, "intf %p id %p\n", intf, id);
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index a3132a9..2ba22cd 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -86,7 +86,7 @@ static void nvdimm_bus_probe_end(struct nvdimm_bus *nvdimm_bus)
{
nvdimm_bus_lock(&nvdimm_bus->dev);
if (--nvdimm_bus->probe_active == 0)
- wake_up(&nvdimm_bus->probe_wait);
+ wake_up(&nvdimm_bus->wait);
nvdimm_bus_unlock(&nvdimm_bus->dev);
}
@@ -348,7 +348,7 @@ struct nvdimm_bus *nvdimm_bus_register(struct device *parent,
return NULL;
INIT_LIST_HEAD(&nvdimm_bus->list);
INIT_LIST_HEAD(&nvdimm_bus->mapping_list);
- init_waitqueue_head(&nvdimm_bus->probe_wait);
+ init_waitqueue_head(&nvdimm_bus->wait);
nvdimm_bus->id = ida_simple_get(&nd_ida, 0, 0, GFP_KERNEL);
mutex_init(&nvdimm_bus->reconfig_mutex);
badrange_init(&nvdimm_bus->badrange);
@@ -418,6 +418,9 @@ static int nd_bus_remove(struct device *dev)
list_del_init(&nvdimm_bus->list);
mutex_unlock(&nvdimm_bus_list_mutex);
+ wait_event(nvdimm_bus->wait,
+ atomic_read(&nvdimm_bus->ioctl_active) == 0);
+
nd_synchronize();
device_for_each_child(&nvdimm_bus->dev, NULL, child_unregister);
@@ -525,13 +528,38 @@ EXPORT_SYMBOL(nd_device_register);
void nd_device_unregister(struct device *dev, enum nd_async_mode mode)
{
+ bool killed;
+
switch (mode) {
case ND_ASYNC:
+ /*
+ * In the async case this is being triggered with the
+ * device lock held and the unregistration work needs to
+ * be moved out of line iff this is thread has won the
+ * race to schedule the deletion.
+ */
+ if (!kill_device(dev))
+ return;
+
get_device(dev);
async_schedule_domain(nd_async_device_unregister, dev,
&nd_async_domain);
break;
case ND_SYNC:
+ /*
+ * In the sync case the device is being unregistered due
+ * to a state change of the parent. Claim the kill state
+ * to synchronize against other unregistration requests,
+ * or otherwise let the async path handle it if the
+ * unregistration was already queued.
+ */
+ device_lock(dev);
+ killed = kill_device(dev);
+ device_unlock(dev);
+
+ if (!killed)
+ return;
+
nd_synchronize();
device_unregister(dev);
break;
@@ -837,10 +865,12 @@ void wait_nvdimm_bus_probe_idle(struct device *dev)
do {
if (nvdimm_bus->probe_active == 0)
break;
- nvdimm_bus_unlock(&nvdimm_bus->dev);
- wait_event(nvdimm_bus->probe_wait,
+ nvdimm_bus_unlock(dev);
+ device_unlock(dev);
+ wait_event(nvdimm_bus->wait,
nvdimm_bus->probe_active == 0);
- nvdimm_bus_lock(&nvdimm_bus->dev);
+ device_lock(dev);
+ nvdimm_bus_lock(dev);
} while (true);
}
@@ -923,20 +953,19 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
int read_only, unsigned int ioctl_cmd, unsigned long arg)
{
struct nvdimm_bus_descriptor *nd_desc = nvdimm_bus->nd_desc;
- static char out_env[ND_CMD_MAX_ENVELOPE];
- static char in_env[ND_CMD_MAX_ENVELOPE];
const struct nd_cmd_desc *desc = NULL;
unsigned int cmd = _IOC_NR(ioctl_cmd);
struct device *dev = &nvdimm_bus->dev;
void __user *p = (void __user *) arg;
+ char *out_env = NULL, *in_env = NULL;
const char *cmd_name, *dimm_name;
u32 in_len = 0, out_len = 0;
unsigned int func = cmd;
unsigned long cmd_mask;
struct nd_cmd_pkg pkg;
int rc, i, cmd_rc;
+ void *buf = NULL;
u64 buf_len = 0;
- void *buf;
if (nvdimm) {
desc = nd_cmd_dimm_desc(cmd);
@@ -967,7 +996,7 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
case ND_CMD_ARS_START:
case ND_CMD_CLEAR_ERROR:
case ND_CMD_CALL:
- dev_dbg(&nvdimm_bus->dev, "'%s' command while read-only.\n",
+ dev_dbg(dev, "'%s' command while read-only.\n",
nvdimm ? nvdimm_cmd_name(cmd)
: nvdimm_bus_cmd_name(cmd));
return -EPERM;
@@ -976,6 +1005,9 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
}
/* process an input envelope */
+ in_env = kzalloc(ND_CMD_MAX_ENVELOPE, GFP_KERNEL);
+ if (!in_env)
+ return -ENOMEM;
for (i = 0; i < desc->in_num; i++) {
u32 in_size, copy;
@@ -983,14 +1015,17 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
if (in_size == UINT_MAX) {
dev_err(dev, "%s:%s unknown input size cmd: %s field: %d\n",
__func__, dimm_name, cmd_name, i);
- return -ENXIO;
+ rc = -ENXIO;
+ goto out;
}
- if (in_len < sizeof(in_env))
- copy = min_t(u32, sizeof(in_env) - in_len, in_size);
+ if (in_len < ND_CMD_MAX_ENVELOPE)
+ copy = min_t(u32, ND_CMD_MAX_ENVELOPE - in_len, in_size);
else
copy = 0;
- if (copy && copy_from_user(&in_env[in_len], p + in_len, copy))
- return -EFAULT;
+ if (copy && copy_from_user(&in_env[in_len], p + in_len, copy)) {
+ rc = -EFAULT;
+ goto out;
+ }
in_len += in_size;
}
@@ -1002,6 +1037,12 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
}
/* process an output envelope */
+ out_env = kzalloc(ND_CMD_MAX_ENVELOPE, GFP_KERNEL);
+ if (!out_env) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
for (i = 0; i < desc->out_num; i++) {
u32 out_size = nd_cmd_out_size(nvdimm, cmd, desc, i,
(u32 *) in_env, (u32 *) out_env, 0);
@@ -1010,15 +1051,18 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
if (out_size == UINT_MAX) {
dev_dbg(dev, "%s unknown output size cmd: %s field: %d\n",
dimm_name, cmd_name, i);
- return -EFAULT;
+ rc = -EFAULT;
+ goto out;
}
- if (out_len < sizeof(out_env))
- copy = min_t(u32, sizeof(out_env) - out_len, out_size);
+ if (out_len < ND_CMD_MAX_ENVELOPE)
+ copy = min_t(u32, ND_CMD_MAX_ENVELOPE - out_len, out_size);
else
copy = 0;
if (copy && copy_from_user(&out_env[out_len],
- p + in_len + out_len, copy))
- return -EFAULT;
+ p + in_len + out_len, copy)) {
+ rc = -EFAULT;
+ goto out;
+ }
out_len += out_size;
}
@@ -1026,19 +1070,23 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
if (buf_len > ND_IOCTL_MAX_BUFLEN) {
dev_dbg(dev, "%s cmd: %s buf_len: %llu > %d\n", dimm_name,
cmd_name, buf_len, ND_IOCTL_MAX_BUFLEN);
- return -EINVAL;
+ rc = -EINVAL;
+ goto out;
}
buf = vmalloc(buf_len);
- if (!buf)
- return -ENOMEM;
+ if (!buf) {
+ rc = -ENOMEM;
+ goto out;
+ }
if (copy_from_user(buf, p, buf_len)) {
rc = -EFAULT;
goto out;
}
- nvdimm_bus_lock(&nvdimm_bus->dev);
+ device_lock(dev);
+ nvdimm_bus_lock(dev);
rc = nd_cmd_clear_to_send(nvdimm_bus, nvdimm, func, buf);
if (rc)
goto out_unlock;
@@ -1053,39 +1101,24 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
nvdimm_account_cleared_poison(nvdimm_bus, clear_err->address,
clear_err->cleared);
}
- nvdimm_bus_unlock(&nvdimm_bus->dev);
if (copy_to_user(p, buf, buf_len))
rc = -EFAULT;
- vfree(buf);
- return rc;
-
- out_unlock:
- nvdimm_bus_unlock(&nvdimm_bus->dev);
- out:
+out_unlock:
+ nvdimm_bus_unlock(dev);
+ device_unlock(dev);
+out:
+ kfree(in_env);
+ kfree(out_env);
vfree(buf);
return rc;
}
-static long nd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- long id = (long) file->private_data;
- int rc = -ENXIO, ro;
- struct nvdimm_bus *nvdimm_bus;
-
- ro = ((file->f_flags & O_ACCMODE) == O_RDONLY);
- mutex_lock(&nvdimm_bus_list_mutex);
- list_for_each_entry(nvdimm_bus, &nvdimm_bus_list, list) {
- if (nvdimm_bus->id == id) {
- rc = __nd_ioctl(nvdimm_bus, NULL, ro, cmd, arg);
- break;
- }
- }
- mutex_unlock(&nvdimm_bus_list_mutex);
-
- return rc;
-}
+enum nd_ioctl_mode {
+ BUS_IOCTL,
+ DIMM_IOCTL,
+};
static int match_dimm(struct device *dev, void *data)
{
@@ -1100,31 +1133,62 @@ static int match_dimm(struct device *dev, void *data)
return 0;
}
-static long nvdimm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+static long nd_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
+ enum nd_ioctl_mode mode)
+
{
- int rc = -ENXIO, ro;
- struct nvdimm_bus *nvdimm_bus;
+ struct nvdimm_bus *nvdimm_bus, *found = NULL;
+ long id = (long) file->private_data;
+ struct nvdimm *nvdimm = NULL;
+ int rc, ro;
ro = ((file->f_flags & O_ACCMODE) == O_RDONLY);
mutex_lock(&nvdimm_bus_list_mutex);
list_for_each_entry(nvdimm_bus, &nvdimm_bus_list, list) {
- struct device *dev = device_find_child(&nvdimm_bus->dev,
- file->private_data, match_dimm);
- struct nvdimm *nvdimm;
+ if (mode == DIMM_IOCTL) {
+ struct device *dev;
- if (!dev)
- continue;
+ dev = device_find_child(&nvdimm_bus->dev,
+ file->private_data, match_dimm);
+ if (!dev)
+ continue;
+ nvdimm = to_nvdimm(dev);
+ found = nvdimm_bus;
+ } else if (nvdimm_bus->id == id) {
+ found = nvdimm_bus;
+ }
- nvdimm = to_nvdimm(dev);
- rc = __nd_ioctl(nvdimm_bus, nvdimm, ro, cmd, arg);
- put_device(dev);
- break;
+ if (found) {
+ atomic_inc(&nvdimm_bus->ioctl_active);
+ break;
+ }
}
mutex_unlock(&nvdimm_bus_list_mutex);
+ if (!found)
+ return -ENXIO;
+
+ nvdimm_bus = found;
+ rc = __nd_ioctl(nvdimm_bus, nvdimm, ro, cmd, arg);
+
+ if (nvdimm)
+ put_device(&nvdimm->dev);
+ if (atomic_dec_and_test(&nvdimm_bus->ioctl_active))
+ wake_up(&nvdimm_bus->wait);
+
return rc;
}
+static long bus_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ return nd_ioctl(file, cmd, arg, BUS_IOCTL);
+}
+
+static long dimm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ return nd_ioctl(file, cmd, arg, DIMM_IOCTL);
+}
+
static int nd_open(struct inode *inode, struct file *file)
{
long minor = iminor(inode);
@@ -1136,16 +1200,16 @@ static int nd_open(struct inode *inode, struct file *file)
static const struct file_operations nvdimm_bus_fops = {
.owner = THIS_MODULE,
.open = nd_open,
- .unlocked_ioctl = nd_ioctl,
- .compat_ioctl = nd_ioctl,
+ .unlocked_ioctl = bus_ioctl,
+ .compat_ioctl = bus_ioctl,
.llseek = noop_llseek,
};
static const struct file_operations nvdimm_fops = {
.owner = THIS_MODULE,
.open = nd_open,
- .unlocked_ioctl = nvdimm_ioctl,
- .compat_ioctl = nvdimm_ioctl,
+ .unlocked_ioctl = dimm_ioctl,
+ .compat_ioctl = dimm_ioctl,
.llseek = noop_llseek,
};
diff --git a/drivers/nvdimm/dax_devs.c b/drivers/nvdimm/dax_devs.c
index 0453f49..326f02f 100644
--- a/drivers/nvdimm/dax_devs.c
+++ b/drivers/nvdimm/dax_devs.c
@@ -126,7 +126,7 @@ int nd_dax_probe(struct device *dev, struct nd_namespace_common *ndns)
nvdimm_bus_unlock(&ndns->dev);
if (!dax_dev)
return -ENOMEM;
- pfn_sb = devm_kzalloc(dev, sizeof(*pfn_sb), GFP_KERNEL);
+ pfn_sb = devm_kmalloc(dev, sizeof(*pfn_sb), GFP_KERNEL);
nd_pfn->pfn_sb = pfn_sb;
rc = nd_pfn_validate(nd_pfn, DAX_SIG);
dev_dbg(dev, "dax: %s\n", rc == 0 ? dev_name(dax_dev) : "<none>");
diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h
index 5ff254d..adf62a6 100644
--- a/drivers/nvdimm/nd-core.h
+++ b/drivers/nvdimm/nd-core.h
@@ -25,10 +25,11 @@ extern int nvdimm_major;
struct nvdimm_bus {
struct nvdimm_bus_descriptor *nd_desc;
- wait_queue_head_t probe_wait;
+ wait_queue_head_t wait;
struct list_head list;
struct device dev;
int id, probe_active;
+ atomic_t ioctl_active;
struct list_head mapping_list;
struct mutex reconfig_mutex;
struct badrange badrange;
diff --git a/drivers/nvdimm/pfn.h b/drivers/nvdimm/pfn.h
index dde9853..e901e3a 100644
--- a/drivers/nvdimm/pfn.h
+++ b/drivers/nvdimm/pfn.h
@@ -36,6 +36,7 @@ struct nd_pfn_sb {
__le32 end_trunc;
/* minor-version-2 record the base alignment of the mapping */
__le32 align;
+ /* minor-version-3 guarantee the padding and flags are zero */
u8 padding[4000];
__le64 checksum;
};
diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c
index 3ee995a..86ed09b 100644
--- a/drivers/nvdimm/pfn_devs.c
+++ b/drivers/nvdimm/pfn_devs.c
@@ -361,6 +361,15 @@ struct device *nd_pfn_create(struct nd_region *nd_region)
return dev;
}
+/**
+ * nd_pfn_validate - read and validate info-block
+ * @nd_pfn: fsdax namespace runtime state / properties
+ * @sig: 'devdax' or 'fsdax' signature
+ *
+ * Upon return the info-block buffer contents (->pfn_sb) are
+ * indeterminate when validation fails, and a coherent info-block
+ * otherwise.
+ */
int nd_pfn_validate(struct nd_pfn *nd_pfn, const char *sig)
{
u64 checksum, offset;
@@ -506,7 +515,7 @@ int nd_pfn_probe(struct device *dev, struct nd_namespace_common *ndns)
nvdimm_bus_unlock(&ndns->dev);
if (!pfn_dev)
return -ENOMEM;
- pfn_sb = devm_kzalloc(dev, sizeof(*pfn_sb), GFP_KERNEL);
+ pfn_sb = devm_kmalloc(dev, sizeof(*pfn_sb), GFP_KERNEL);
nd_pfn = to_nd_pfn(pfn_dev);
nd_pfn->pfn_sb = pfn_sb;
rc = nd_pfn_validate(nd_pfn, PFN_SIG);
@@ -638,7 +647,7 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
u64 checksum;
int rc;
- pfn_sb = devm_kzalloc(&nd_pfn->dev, sizeof(*pfn_sb), GFP_KERNEL);
+ pfn_sb = devm_kmalloc(&nd_pfn->dev, sizeof(*pfn_sb), GFP_KERNEL);
if (!pfn_sb)
return -ENOMEM;
@@ -647,11 +656,14 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
sig = DAX_SIG;
else
sig = PFN_SIG;
+
rc = nd_pfn_validate(nd_pfn, sig);
if (rc != -ENODEV)
return rc;
/* no info block, do init */;
+ memset(pfn_sb, 0, sizeof(*pfn_sb));
+
nd_region = to_nd_region(nd_pfn->dev.parent);
if (nd_region->ro) {
dev_info(&nd_pfn->dev,
@@ -705,7 +717,7 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
memcpy(pfn_sb->uuid, nd_pfn->uuid, 16);
memcpy(pfn_sb->parent_uuid, nd_dev_to_uuid(&ndns->dev), 16);
pfn_sb->version_major = cpu_to_le16(1);
- pfn_sb->version_minor = cpu_to_le16(2);
+ pfn_sb->version_minor = cpu_to_le16(3);
pfn_sb->start_pad = cpu_to_le32(start_pad);
pfn_sb->end_trunc = cpu_to_le32(end_trunc);
pfn_sb->align = cpu_to_le32(nd_pfn->align);
diff --git a/drivers/nvdimm/region.c b/drivers/nvdimm/region.c
index b9ca003..f9130cc 100644
--- a/drivers/nvdimm/region.c
+++ b/drivers/nvdimm/region.c
@@ -42,17 +42,6 @@ static int nd_region_probe(struct device *dev)
if (rc)
return rc;
- rc = nd_region_register_namespaces(nd_region, &err);
- if (rc < 0)
- return rc;
-
- ndrd = dev_get_drvdata(dev);
- ndrd->ns_active = rc;
- ndrd->ns_count = rc + err;
-
- if (rc && err && rc == err)
- return -ENODEV;
-
if (is_nd_pmem(&nd_region->dev)) {
struct resource ndr_res;
@@ -68,6 +57,17 @@ static int nd_region_probe(struct device *dev)
nvdimm_badblocks_populate(nd_region, &nd_region->bb, &ndr_res);
}
+ rc = nd_region_register_namespaces(nd_region, &err);
+ if (rc < 0)
+ return rc;
+
+ ndrd = dev_get_drvdata(dev);
+ ndrd->ns_active = rc;
+ ndrd->ns_count = rc + err;
+
+ if (rc && err && rc == err)
+ return -ENODEV;
+
nd_region->btt_seed = nd_btt_create(nd_region);
nd_region->pfn_seed = nd_pfn_create(nd_region);
nd_region->dax_seed = nd_dax_create(nd_region);
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c
index e7377f1..0303296 100644
--- a/drivers/nvdimm/region_devs.c
+++ b/drivers/nvdimm/region_devs.c
@@ -425,10 +425,12 @@ static ssize_t available_size_show(struct device *dev,
* memory nvdimm_bus_lock() is dropped, but that's userspace's
* problem to not race itself.
*/
+ device_lock(dev);
nvdimm_bus_lock(dev);
wait_nvdimm_bus_probe_idle(dev);
available = nd_region_available_dpa(nd_region);
nvdimm_bus_unlock(dev);
+ device_unlock(dev);
return sprintf(buf, "%llu\n", available);
}
@@ -440,10 +442,12 @@ static ssize_t max_available_extent_show(struct device *dev,
struct nd_region *nd_region = to_nd_region(dev);
unsigned long long available = 0;
+ device_lock(dev);
nvdimm_bus_lock(dev);
wait_nvdimm_bus_probe_idle(dev);
available = nd_region_allocatable_dpa(nd_region);
nvdimm_bus_unlock(dev);
+ device_unlock(dev);
return sprintf(buf, "%llu\n", available);
}
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index d8869d9..e26d119 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -3168,6 +3168,14 @@ static void nvme_ns_remove(struct nvme_ns *ns)
return;
nvme_fault_inject_fini(ns);
+
+ mutex_lock(&ns->ctrl->subsys->lock);
+ list_del_rcu(&ns->siblings);
+ mutex_unlock(&ns->ctrl->subsys->lock);
+ synchronize_rcu(); /* guarantee not available in head->list */
+ nvme_mpath_clear_current_path(ns);
+ synchronize_srcu(&ns->head->srcu); /* wait for concurrent submissions */
+
if (ns->disk && ns->disk->flags & GENHD_FL_UP) {
sysfs_remove_group(&disk_to_dev(ns->disk)->kobj,
&nvme_ns_id_attr_group);
@@ -3179,16 +3187,10 @@ static void nvme_ns_remove(struct nvme_ns *ns)
blk_integrity_unregister(ns->disk);
}
- mutex_lock(&ns->ctrl->subsys->lock);
- list_del_rcu(&ns->siblings);
- nvme_mpath_clear_current_path(ns);
- mutex_unlock(&ns->ctrl->subsys->lock);
-
down_write(&ns->ctrl->namespaces_rwsem);
list_del_init(&ns->list);
up_write(&ns->ctrl->namespaces_rwsem);
- synchronize_srcu(&ns->head->srcu);
nvme_mpath_check_last_path(ns);
nvme_put_ns(ns);
}
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index c8eeecc..0a5d064 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -2253,11 +2253,13 @@ static void nvme_reset_work(struct work_struct *work)
struct nvme_dev *dev =
container_of(work, struct nvme_dev, ctrl.reset_work);
bool was_suspend = !!(dev->ctrl.ctrl_config & NVME_CC_SHN_NORMAL);
- int result = -ENODEV;
+ int result;
enum nvme_ctrl_state new_state = NVME_CTRL_LIVE;
- if (WARN_ON(dev->ctrl.state != NVME_CTRL_RESETTING))
+ if (WARN_ON(dev->ctrl.state != NVME_CTRL_RESETTING)) {
+ result = -ENODEV;
goto out;
+ }
/*
* If we're called to reset a live controller first shut it down before
@@ -2294,6 +2296,7 @@ static void nvme_reset_work(struct work_struct *work)
if (!nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_CONNECTING)) {
dev_warn(dev->ctrl.device,
"failed to mark controller CONNECTING\n");
+ result = -EBUSY;
goto out;
}
@@ -2354,6 +2357,7 @@ static void nvme_reset_work(struct work_struct *work)
if (!nvme_change_ctrl_state(&dev->ctrl, new_state)) {
dev_warn(dev->ctrl.device,
"failed to mark controller state %d\n", new_state);
+ result = -ENODEV;
goto out;
}
diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c
index a32d6dd..412524a 100644
--- a/drivers/pci/controller/dwc/pci-dra7xx.c
+++ b/drivers/pci/controller/dwc/pci-dra7xx.c
@@ -26,6 +26,7 @@
#include <linux/types.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
+#include <linux/gpio/consumer.h>
#include "../../pci.h"
#include "pcie-designware.h"
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
index 4352c1c..87a8887 100644
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -178,6 +178,8 @@ static void qcom_ep_reset_assert(struct qcom_pcie *pcie)
static void qcom_ep_reset_deassert(struct qcom_pcie *pcie)
{
+ /* Ensure that PERST has been asserted for at least 100 ms */
+ msleep(100);
gpiod_set_value_cansleep(pcie->reset, 0);
usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500);
}
diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c
index 808a182..5dadc96 100644
--- a/drivers/pci/controller/pci-hyperv.c
+++ b/drivers/pci/controller/pci-hyperv.c
@@ -1880,6 +1880,7 @@ static void hv_pci_devices_present(struct hv_pcibus_device *hbus,
static void hv_eject_device_work(struct work_struct *work)
{
struct pci_eject_response *ejct_pkt;
+ struct hv_pcibus_device *hbus;
struct hv_pci_dev *hpdev;
struct pci_dev *pdev;
unsigned long flags;
@@ -1890,6 +1891,7 @@ static void hv_eject_device_work(struct work_struct *work)
} ctxt;
hpdev = container_of(work, struct hv_pci_dev, wrk);
+ hbus = hpdev->hbus;
WARN_ON(hpdev->state != hv_pcichild_ejecting);
@@ -1900,8 +1902,7 @@ static void hv_eject_device_work(struct work_struct *work)
* because hbus->pci_bus may not exist yet.
*/
wslot = wslot_to_devfn(hpdev->desc.win_slot.slot);
- pdev = pci_get_domain_bus_and_slot(hpdev->hbus->sysdata.domain, 0,
- wslot);
+ pdev = pci_get_domain_bus_and_slot(hbus->sysdata.domain, 0, wslot);
if (pdev) {
pci_lock_rescan_remove();
pci_stop_and_remove_bus_device(pdev);
@@ -1909,9 +1910,9 @@ static void hv_eject_device_work(struct work_struct *work)
pci_unlock_rescan_remove();
}
- spin_lock_irqsave(&hpdev->hbus->device_list_lock, flags);
+ spin_lock_irqsave(&hbus->device_list_lock, flags);
list_del(&hpdev->list_entry);
- spin_unlock_irqrestore(&hpdev->hbus->device_list_lock, flags);
+ spin_unlock_irqrestore(&hbus->device_list_lock, flags);
if (hpdev->pci_slot)
pci_destroy_slot(hpdev->pci_slot);
@@ -1920,7 +1921,7 @@ static void hv_eject_device_work(struct work_struct *work)
ejct_pkt = (struct pci_eject_response *)&ctxt.pkt.message;
ejct_pkt->message_type.type = PCI_EJECTION_COMPLETE;
ejct_pkt->wslot.slot = hpdev->desc.win_slot.slot;
- vmbus_sendpacket(hpdev->hbus->hdev->channel, ejct_pkt,
+ vmbus_sendpacket(hbus->hdev->channel, ejct_pkt,
sizeof(*ejct_pkt), (unsigned long)&ctxt.pkt,
VM_PKT_DATA_INBAND, 0);
@@ -1929,7 +1930,9 @@ static void hv_eject_device_work(struct work_struct *work)
/* For the two refs got in new_pcichild_device() */
put_pcichild(hpdev);
put_pcichild(hpdev);
- put_hvpcibus(hpdev->hbus);
+ /* hpdev has been freed. Do not use it any more. */
+
+ put_hvpcibus(hbus);
}
/**
diff --git a/drivers/pci/controller/pcie-mobiveil.c b/drivers/pci/controller/pcie-mobiveil.c
index a939e8d3..a2d1e89 100644
--- a/drivers/pci/controller/pcie-mobiveil.c
+++ b/drivers/pci/controller/pcie-mobiveil.c
@@ -508,6 +508,12 @@ static int mobiveil_host_init(struct mobiveil_pcie *pcie)
return err;
}
+ /* setup bus numbers */
+ value = csr_readl(pcie, PCI_PRIMARY_BUS);
+ value &= 0xff000000;
+ value |= 0x00ff0100;
+ csr_writel(pcie, value, PCI_PRIMARY_BUS);
+
/*
* program Bus Master Enable Bit in Command Register in PAB Config
* Space
@@ -547,7 +553,7 @@ static int mobiveil_host_init(struct mobiveil_pcie *pcie)
resource_size(pcie->ob_io_res));
/* memory inbound translation window */
- program_ib_windows(pcie, WIN_NUM_1, 0, MEM_WINDOW_TYPE, IB_WIN_SIZE);
+ program_ib_windows(pcie, WIN_NUM_0, 0, MEM_WINDOW_TYPE, IB_WIN_SIZE);
/* Get the I/O and memory ranges from DT */
resource_list_for_each_entry_safe(win, tmp, &pcie->resources) {
@@ -559,11 +565,18 @@ static int mobiveil_host_init(struct mobiveil_pcie *pcie)
if (type) {
/* configure outbound translation window */
program_ob_windows(pcie, pcie->ob_wins_configured,
- win->res->start, 0, type,
- resource_size(win->res));
+ win->res->start,
+ win->res->start - win->offset,
+ type, resource_size(win->res));
}
}
+ /* fixup for PCIe class register */
+ value = csr_readl(pcie, PAB_INTP_AXI_PIO_CLASS);
+ value &= 0xff;
+ value |= (PCI_CLASS_BRIDGE_PCI << 16);
+ csr_writel(pcie, value, PAB_INTP_AXI_PIO_CLASS);
+
/* setup MSI hardware registers */
mobiveil_pcie_enable_msi(pcie);
@@ -804,9 +817,6 @@ static int mobiveil_pcie_probe(struct platform_device *pdev)
goto error;
}
- /* fixup for PCIe class register */
- csr_writel(pcie, 0x060402ab, PAB_INTP_AXI_PIO_CLASS);
-
/* initialize the IRQ domains */
ret = mobiveil_pcie_init_irq_domain(pcie);
if (ret) {
diff --git a/drivers/pci/controller/pcie-xilinx-nwl.c b/drivers/pci/controller/pcie-xilinx-nwl.c
index fb32840..4850a1b 100644
--- a/drivers/pci/controller/pcie-xilinx-nwl.c
+++ b/drivers/pci/controller/pcie-xilinx-nwl.c
@@ -483,15 +483,13 @@ static int nwl_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
int i;
mutex_lock(&msi->lock);
- bit = bitmap_find_next_zero_area(msi->bitmap, INT_PCI_MSI_NR, 0,
- nr_irqs, 0);
- if (bit >= INT_PCI_MSI_NR) {
+ bit = bitmap_find_free_region(msi->bitmap, INT_PCI_MSI_NR,
+ get_count_order(nr_irqs));
+ if (bit < 0) {
mutex_unlock(&msi->lock);
return -ENOSPC;
}
- bitmap_set(msi->bitmap, bit, nr_irqs);
-
for (i = 0; i < nr_irqs; i++) {
irq_domain_set_info(domain, virq + i, bit + i, &nwl_irq_chip,
domain->host_data, handle_simple_irq,
@@ -509,7 +507,8 @@ static void nwl_irq_domain_free(struct irq_domain *domain, unsigned int virq,
struct nwl_msi *msi = &pcie->msi;
mutex_lock(&msi->lock);
- bitmap_clear(msi->bitmap, data->hwirq, nr_irqs);
+ bitmap_release_region(msi->bitmap, data->hwirq,
+ get_count_order(nr_irqs));
mutex_unlock(&msi->lock);
}
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 75b7f2c..f06ca58 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -414,6 +414,9 @@ static int pci_device_probe(struct device *dev)
struct pci_dev *pci_dev = to_pci_dev(dev);
struct pci_driver *drv = to_pci_driver(dev->driver);
+ if (!pci_device_can_probe(pci_dev))
+ return -ENODEV;
+
pci_assign_irq(pci_dev);
error = pcibios_alloc_irq(pci_dev);
@@ -421,12 +424,10 @@ static int pci_device_probe(struct device *dev)
return error;
pci_dev_get(pci_dev);
- if (pci_device_can_probe(pci_dev)) {
- error = __pci_device_probe(drv, pci_dev);
- if (error) {
- pcibios_free_irq(pci_dev);
- pci_dev_put(pci_dev);
- }
+ error = __pci_device_probe(drv, pci_dev);
+ if (error) {
+ pcibios_free_irq(pci_dev);
+ pci_dev_put(pci_dev);
}
return error;
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 9ecfe13..1edf5a1 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -478,7 +478,7 @@ static ssize_t remove_store(struct device *dev, struct device_attribute *attr,
pci_stop_and_remove_bus_device_locked(to_pci_dev(dev));
return count;
}
-static struct device_attribute dev_remove_attr = __ATTR(remove,
+static struct device_attribute dev_remove_attr = __ATTR_IGNORE_LOCKDEP(remove,
(S_IWUSR|S_IWGRP),
NULL, remove_store);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 61f2ef2..c654653 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -2004,6 +2004,13 @@ static void pci_pme_list_scan(struct work_struct *work)
*/
if (bridge && bridge->current_state != PCI_D0)
continue;
+ /*
+ * If the device is in D3cold it should not be
+ * polled either.
+ */
+ if (pme_dev->dev->current_state == PCI_D3cold)
+ continue;
+
pci_pme_wakeup(pme_dev->dev, NULL);
} else {
list_del(&pme_dev->list);
diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
index ed711a0..86c6c53 100644
--- a/drivers/perf/arm_pmu.c
+++ b/drivers/perf/arm_pmu.c
@@ -733,8 +733,8 @@ static int cpu_pm_pmu_notify(struct notifier_block *b, unsigned long cmd,
cpu_pm_pmu_setup(armpmu, cmd);
break;
case CPU_PM_EXIT:
- cpu_pm_pmu_setup(armpmu, cmd);
case CPU_PM_ENTER_FAILED:
+ cpu_pm_pmu_setup(armpmu, cmd);
armpmu->start(armpmu);
break;
default:
diff --git a/drivers/phy/renesas/phy-rcar-gen2.c b/drivers/phy/renesas/phy-rcar-gen2.c
index 97d4dd6..aa02b19 100644
--- a/drivers/phy/renesas/phy-rcar-gen2.c
+++ b/drivers/phy/renesas/phy-rcar-gen2.c
@@ -288,6 +288,7 @@ static int rcar_gen2_phy_probe(struct platform_device *pdev)
error = of_property_read_u32(np, "reg", &channel_num);
if (error || channel_num > 2) {
dev_err(dev, "Invalid \"reg\" property\n");
+ of_node_put(np);
return error;
}
channel->select_mask = select_mask[channel_num];
@@ -303,6 +304,7 @@ static int rcar_gen2_phy_probe(struct platform_device *pdev)
&rcar_gen2_phy_ops);
if (IS_ERR(phy->phy)) {
dev_err(dev, "Failed to create PHY\n");
+ of_node_put(np);
return PTR_ERR(phy->phy);
}
phy_set_drvdata(phy->phy, phy);
diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c
index a613e54..564cfae 100644
--- a/drivers/pinctrl/mediatek/mtk-eint.c
+++ b/drivers/pinctrl/mediatek/mtk-eint.c
@@ -113,6 +113,8 @@ static void mtk_eint_mask(struct irq_data *d)
void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq,
eint->regs->mask_set);
+ eint->cur_mask[d->hwirq >> 5] &= ~mask;
+
writel(mask, reg);
}
@@ -123,6 +125,8 @@ static void mtk_eint_unmask(struct irq_data *d)
void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq,
eint->regs->mask_clr);
+ eint->cur_mask[d->hwirq >> 5] |= mask;
+
writel(mask, reg);
if (eint->dual_edge[d->hwirq])
@@ -217,19 +221,6 @@ static void mtk_eint_chip_write_mask(const struct mtk_eint *eint,
}
}
-static void mtk_eint_chip_read_mask(const struct mtk_eint *eint,
- void __iomem *base, u32 *buf)
-{
- int port;
- void __iomem *reg;
-
- for (port = 0; port < eint->hw->ports; port++) {
- reg = base + eint->regs->mask + (port << 2);
- buf[port] = ~readl_relaxed(reg);
- /* Mask is 0 when irq is enabled, and 1 when disabled. */
- }
-}
-
static int mtk_eint_irq_request_resources(struct irq_data *d)
{
struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
@@ -318,7 +309,7 @@ static void mtk_eint_irq_handler(struct irq_desc *desc)
struct irq_chip *chip = irq_desc_get_chip(desc);
struct mtk_eint *eint = irq_desc_get_handler_data(desc);
unsigned int status, eint_num;
- int offset, index, virq;
+ int offset, mask_offset, index, virq;
void __iomem *reg = mtk_eint_get_offset(eint, 0, eint->regs->stat);
int dual_edge, start_level, curr_level;
@@ -328,10 +319,24 @@ static void mtk_eint_irq_handler(struct irq_desc *desc)
status = readl(reg);
while (status) {
offset = __ffs(status);
+ mask_offset = eint_num >> 5;
index = eint_num + offset;
virq = irq_find_mapping(eint->domain, index);
status &= ~BIT(offset);
+ /*
+ * If we get an interrupt on pin that was only required
+ * for wake (but no real interrupt requested), mask the
+ * interrupt (as would mtk_eint_resume do anyway later
+ * in the resume sequence).
+ */
+ if (eint->wake_mask[mask_offset] & BIT(offset) &&
+ !(eint->cur_mask[mask_offset] & BIT(offset))) {
+ writel_relaxed(BIT(offset), reg -
+ eint->regs->stat +
+ eint->regs->mask_set);
+ }
+
dual_edge = eint->dual_edge[index];
if (dual_edge) {
/*
@@ -370,7 +375,6 @@ static void mtk_eint_irq_handler(struct irq_desc *desc)
int mtk_eint_do_suspend(struct mtk_eint *eint)
{
- mtk_eint_chip_read_mask(eint, eint->base, eint->cur_mask);
mtk_eint_chip_write_mask(eint, eint->base, eint->wake_mask);
return 0;
diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c
index cecbce2..33c3eca 100644
--- a/drivers/pinctrl/pinctrl-mcp23s08.c
+++ b/drivers/pinctrl/pinctrl-mcp23s08.c
@@ -889,6 +889,10 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
if (ret < 0)
goto fail;
+ ret = devm_gpiochip_add_data(dev, &mcp->chip, mcp);
+ if (ret < 0)
+ goto fail;
+
mcp->irq_controller =
device_property_read_bool(dev, "interrupt-controller");
if (mcp->irq && mcp->irq_controller) {
@@ -930,10 +934,6 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
goto fail;
}
- ret = devm_gpiochip_add_data(dev, &mcp->chip, mcp);
- if (ret < 0)
- goto fail;
-
if (one_regmap_config) {
mcp->pinctrl_desc.name = devm_kasprintf(dev, GFP_KERNEL,
"mcp23xxx-pinctrl.%d", raw_chip_address);
diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index f4a6142..8d83817 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -3172,6 +3172,7 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank,
base,
&rockchip_regmap_config);
}
+ of_node_put(node);
}
bank->irq = irq_of_parse_and_map(bank->of_node, 0);
diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c
index 0e3fc66..537e8cf 100644
--- a/drivers/platform/msm/gsi/gsi.c
+++ b/drivers/platform/msm/gsi/gsi.c
@@ -486,12 +486,12 @@ static uint16_t gsi_get_complete_num(struct gsi_ring_ctx *ctx, uint64_t addr1,
GSIDBG_LOW("gsi base addr 0x%llx end addr 0x%llx\n",
ctx->base, ctx->end);
- if (addr1 < ctx->base || addr1 >= ctx->end) {
+ if (unlikely(addr1 < ctx->base || addr1 >= ctx->end)) {
GSIERR("address = 0x%llx not in range\n", addr1);
GSI_ASSERT();
}
- if (addr2 < ctx->base || addr2 >= ctx->end) {
+ if (unlikely(addr2 < ctx->base || addr2 >= ctx->end)) {
GSIERR("address = 0x%llx not in range\n", addr2);
GSI_ASSERT();
}
@@ -512,14 +512,14 @@ static void gsi_process_chan(struct gsi_xfer_compl_evt *evt,
uint64_t rp;
ch_id = evt->chid;
- if (WARN_ON(ch_id >= gsi_ctx->max_ch)) {
+ if (unlikely(WARN_ON(ch_id >= gsi_ctx->max_ch))) {
GSIERR("Unexpected ch %d\n", ch_id);
return;
}
ch_ctx = &gsi_ctx->chan[ch_id];
- if (WARN_ON(ch_ctx->props.prot != GSI_CHAN_PROT_GPI &&
- ch_ctx->props.prot != GSI_CHAN_PROT_GCI))
+ if (unlikely(WARN_ON(ch_ctx->props.prot != GSI_CHAN_PROT_GPI &&
+ ch_ctx->props.prot != GSI_CHAN_PROT_GCI)))
return;
if (evt->type != GSI_XFER_COMPL_TYPE_GCI) {
@@ -555,7 +555,7 @@ static void gsi_process_chan(struct gsi_xfer_compl_evt *evt,
notify->bytes_xfered = evt->len;
if (callback) {
- if (atomic_read(&ch_ctx->poll_mode)) {
+ if (unlikely(atomic_read(&ch_ctx->poll_mode))) {
GSIERR("Calling client callback in polling mode\n");
WARN_ON(1);
}
@@ -633,7 +633,8 @@ static void gsi_handle_ieob(int ee)
for (i = 0; i < GSI_STTS_REG_BITS; i++) {
if ((1 << i) & ch & msk) {
- if (i >= gsi_ctx->max_ev || i >= GSI_EVT_RING_MAX) {
+ if (unlikely(i >= gsi_ctx->max_ev
+ || i >= GSI_EVT_RING_MAX)) {
GSIERR("invalid event %d\n", i);
break;
}
@@ -646,7 +647,8 @@ static void gsi_handle_ieob(int ee)
if (ctx->props.intr == GSI_INTR_MSI)
continue;
- if (ctx->props.intf != GSI_EVT_CHTYPE_GPI_EV) {
+ if (unlikely(ctx->props.intf !=
+ GSI_EVT_CHTYPE_GPI_EV)) {
GSIERR("Unexpected irq intf %d\n",
ctx->props.intf);
GSI_ASSERT();
@@ -780,7 +782,7 @@ static void gsi_handle_irq(void)
if (type & GSI_EE_n_CNTXT_TYPE_IRQ_GENERAL_BMSK)
gsi_handle_general(ee);
- if (++cnt > GSI_ISR_MAX_ITER) {
+ if (unlikely(++cnt > GSI_ISR_MAX_ITER)) {
/*
* Max number of spurious interrupts from hardware.
* Unexpected hardware state.
@@ -942,17 +944,17 @@ int gsi_complete_clk_grant(unsigned long dev_hdl)
{
unsigned long flags;
- if (!gsi_ctx) {
+ if (unlikely(!gsi_ctx)) {
pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__);
return -GSI_STATUS_NODEV;
}
- if (!gsi_ctx->per_registered) {
+ if (unlikely(!gsi_ctx->per_registered)) {
GSIERR("no client registered\n");
return -GSI_STATUS_INVALID_PARAMS;
}
- if (dev_hdl != (uintptr_t)gsi_ctx) {
+ if (unlikely(dev_hdl != (uintptr_t)gsi_ctx)) {
GSIERR("bad params dev_hdl=0x%lx gsi_ctx=0x%pK\n", dev_hdl,
gsi_ctx);
return -GSI_STATUS_INVALID_PARAMS;
@@ -1871,19 +1873,19 @@ int gsi_ring_evt_ring_db(unsigned long evt_ring_hdl, uint64_t value)
{
struct gsi_evt_ctx *ctx;
- if (!gsi_ctx) {
+ if (unlikely(!gsi_ctx)) {
pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__);
return -GSI_STATUS_NODEV;
}
- if (evt_ring_hdl >= gsi_ctx->max_ev) {
+ if (unlikely(evt_ring_hdl >= gsi_ctx->max_ev)) {
GSIERR("bad params evt_ring_hdl=%lu\n", evt_ring_hdl);
return -GSI_STATUS_INVALID_PARAMS;
}
ctx = &gsi_ctx->evtr[evt_ring_hdl];
- if (ctx->state != GSI_EVT_RING_STATE_ALLOCATED) {
+ if (unlikely(ctx->state != GSI_EVT_RING_STATE_ALLOCATED)) {
GSIERR("bad state %d\n",
gsi_ctx->evtr[evt_ring_hdl].state);
return -GSI_STATUS_UNSUPPORTED_OP;
@@ -1901,19 +1903,19 @@ int gsi_ring_ch_ring_db(unsigned long chan_hdl, uint64_t value)
struct gsi_chan_ctx *ctx;
uint32_t val;
- if (!gsi_ctx) {
+ if (unlikely(!gsi_ctx)) {
pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__);
return -GSI_STATUS_NODEV;
}
- if (chan_hdl >= gsi_ctx->max_ch) {
+ if (unlikely(chan_hdl >= gsi_ctx->max_ch)) {
GSIERR("bad chan_hdl=%lu\n", chan_hdl);
return -GSI_STATUS_INVALID_PARAMS;
}
ctx = &gsi_ctx->chan[chan_hdl];
- if (ctx->state != GSI_CHAN_STATE_STARTED) {
+ if (unlikely(ctx->state != GSI_CHAN_STATE_STARTED)) {
GSIERR("bad state %d\n", ctx->state);
return -GSI_STATUS_UNSUPPORTED_OP;
}
@@ -3397,13 +3399,13 @@ int __gsi_populate_gci_tre(struct gsi_chan_ctx *ctx,
uint16_t idx;
memset(&gci_tre, 0, sizeof(gci_tre));
- if (xfer->addr & 0xFFFFFF0000000000) {
+ if (unlikely(xfer->addr & 0xFFFFFF0000000000)) {
GSIERR("chan_hdl=%u add too large=%llx\n",
ctx->props.ch_id, xfer->addr);
return -EINVAL;
}
- if (xfer->type != GSI_XFER_ELEM_DATA) {
+ if (unlikely(xfer->type != GSI_XFER_ELEM_DATA)) {
GSIERR("chan_hdl=%u bad RE type=%u\n", ctx->props.ch_id,
xfer->type);
return -EINVAL;
@@ -3417,7 +3419,7 @@ int __gsi_populate_gci_tre(struct gsi_chan_ctx *ctx,
gci_tre.buf_len = xfer->len;
gci_tre.re_type = GSI_RE_COAL;
gci_tre.cookie = __gsi_get_gci_cookie(ctx, idx);
- if (gci_tre.cookie > (ctx->ring.max_num_elem + GSI_VEID_MAX))
+ if (unlikely(gci_tre.cookie > (ctx->ring.max_num_elem + GSI_VEID_MAX)))
return -EPERM;
/* write the TRE to ring */
@@ -3476,21 +3478,29 @@ int gsi_queue_xfer(unsigned long chan_hdl, uint16_t num_xfers,
spinlock_t *slock;
unsigned long flags;
- if (!gsi_ctx) {
+ if (unlikely(!gsi_ctx)) {
pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__);
return -GSI_STATUS_NODEV;
}
- if (chan_hdl >= gsi_ctx->max_ch || (num_xfers && !xfer)) {
+ if (unlikely(chan_hdl >= gsi_ctx->max_ch || (num_xfers && !xfer))) {
GSIERR("bad params chan_hdl=%lu num_xfers=%u xfer=%pK\n",
chan_hdl, num_xfers, xfer);
return -GSI_STATUS_INVALID_PARAMS;
}
+ if (unlikely(gsi_ctx->chan[chan_hdl].state
+ == GSI_CHAN_STATE_NOT_ALLOCATED)) {
+ GSIERR("bad state %d\n",
+ gsi_ctx->chan[chan_hdl].state);
+ return -GSI_STATUS_UNSUPPORTED_OP;
+ }
+
+
ctx = &gsi_ctx->chan[chan_hdl];
- if (ctx->props.prot != GSI_CHAN_PROT_GPI &&
- ctx->props.prot != GSI_CHAN_PROT_GCI) {
+ if (unlikely(ctx->props.prot != GSI_CHAN_PROT_GPI &&
+ ctx->props.prot != GSI_CHAN_PROT_GCI)) {
GSIERR("op not supported for protocol %u\n", ctx->props.prot);
return -GSI_STATUS_UNSUPPORTED_OP;
}
@@ -3512,7 +3522,7 @@ int gsi_queue_xfer(unsigned long chan_hdl, uint16_t num_xfers,
*/
if (ctx->props.prot != GSI_CHAN_PROT_GCI) {
__gsi_query_channel_free_re(ctx, &free);
- if (num_xfers > free) {
+ if (unlikely(num_xfers > free)) {
GSIERR("chan_hdl=%lu num_xfers=%u free=%u\n",
chan_hdl, num_xfers, free);
spin_unlock_irqrestore(slock, flags);
@@ -3532,7 +3542,7 @@ int gsi_queue_xfer(unsigned long chan_hdl, uint16_t num_xfers,
gsi_incr_ring_wp(&ctx->ring);
}
- if (i != num_xfers) {
+ if (unlikely(i != num_xfers)) {
/* reject all the xfers */
ctx->ring.wp_local = wp_rollback;
spin_unlock_irqrestore(slock, flags);
@@ -3609,13 +3619,13 @@ int gsi_poll_n_channel(unsigned long chan_hdl,
int i;
unsigned long flags;
- if (!gsi_ctx) {
+ if (unlikely(!gsi_ctx)) {
pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__);
return -GSI_STATUS_NODEV;
}
- if (chan_hdl >= gsi_ctx->max_ch || !notify ||
- !actual_num || expected_num <= 0) {
+ if (unlikely(chan_hdl >= gsi_ctx->max_ch || !notify ||
+ !actual_num || expected_num <= 0)) {
GSIERR("bad params chan_hdl=%lu notify=%pK\n",
chan_hdl, notify);
GSIERR("actual_num=%pK expected_num=%d\n",
@@ -3626,13 +3636,13 @@ int gsi_poll_n_channel(unsigned long chan_hdl,
ctx = &gsi_ctx->chan[chan_hdl];
ee = gsi_ctx->per.ee;
- if (ctx->props.prot != GSI_CHAN_PROT_GPI &&
- ctx->props.prot != GSI_CHAN_PROT_GCI) {
+ if (unlikely(ctx->props.prot != GSI_CHAN_PROT_GPI &&
+ ctx->props.prot != GSI_CHAN_PROT_GCI)) {
GSIERR("op not supported for protocol %u\n", ctx->props.prot);
return -GSI_STATUS_UNSUPPORTED_OP;
}
- if (!ctx->evtr) {
+ if (unlikely(!ctx->evtr)) {
GSIERR("no event ring associated chan_hdl=%lu\n", chan_hdl);
return -GSI_STATUS_UNSUPPORTED_OP;
}
@@ -3690,25 +3700,25 @@ int gsi_config_channel_mode(unsigned long chan_hdl, enum gsi_chan_mode mode)
unsigned long flags;
enum gsi_chan_mode chan_mode;
- if (!gsi_ctx) {
+ if (unlikely(!gsi_ctx)) {
pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__);
return -GSI_STATUS_NODEV;
}
- if (chan_hdl >= gsi_ctx->max_ch) {
+ if (unlikely(chan_hdl >= gsi_ctx->max_ch)) {
GSIERR("bad params chan_hdl=%lu mode=%u\n", chan_hdl, mode);
return -GSI_STATUS_INVALID_PARAMS;
}
ctx = &gsi_ctx->chan[chan_hdl];
- if (ctx->props.prot != GSI_CHAN_PROT_GPI &&
- ctx->props.prot != GSI_CHAN_PROT_GCI) {
+ if (unlikely(ctx->props.prot != GSI_CHAN_PROT_GPI &&
+ ctx->props.prot != GSI_CHAN_PROT_GCI)) {
GSIERR("op not supported for protocol %u\n", ctx->props.prot);
return -GSI_STATUS_UNSUPPORTED_OP;
}
- if (!ctx->evtr || !ctx->evtr->props.exclusive) {
+ if (unlikely(!ctx->evtr || !ctx->evtr->props.exclusive)) {
GSIERR("cannot configure mode on chan_hdl=%lu\n",
chan_hdl);
return -GSI_STATUS_UNSUPPORTED_OP;
@@ -3719,7 +3729,7 @@ int gsi_config_channel_mode(unsigned long chan_hdl, enum gsi_chan_mode mode)
else
curr = GSI_CHAN_MODE_CALLBACK;
- if (mode == curr) {
+ if (unlikely(mode == curr)) {
GSIERR("already in requested mode %u chan_hdl=%lu\n",
curr, chan_hdl);
return -GSI_STATUS_UNSUPPORTED_OP;
diff --git a/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c b/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c
index ff70d64..f6fc8c7 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c
@@ -584,7 +584,7 @@ static netdev_tx_t ecm_ipa_start_xmit
}
ret = ipa_pm_activate(ecm_ipa_ctx->pm_hdl);
- if (ret) {
+ if (unlikely(ret)) {
ECM_IPA_DEBUG("Failed to activate PM client\n");
netif_stop_queue(net);
goto fail_pm_activate;
@@ -607,7 +607,7 @@ static netdev_tx_t ecm_ipa_start_xmit
, skb->protocol);
ret = ipa_tx_dp(ecm_ipa_ctx->ipa_to_usb_client, skb, NULL);
- if (ret) {
+ if (unlikely(ret)) {
ECM_IPA_ERROR("ipa transmit failed (%d)\n", ret);
goto fail_tx_packet;
}
@@ -642,7 +642,7 @@ static void ecm_ipa_packet_receive_notify
int result;
unsigned int packet_len;
- if (!skb) {
+ if (unlikely(!skb)) {
ECM_IPA_ERROR("Bad SKB received from IPA driver\n");
return;
}
@@ -655,7 +655,7 @@ static void ecm_ipa_packet_receive_notify
return;
}
- if (evt != IPA_RECEIVE) {
+ if (unlikely(evt != IPA_RECEIVE)) {
ECM_IPA_ERROR("A none IPA_RECEIVE event in ecm_ipa_receive\n");
return;
}
@@ -664,7 +664,7 @@ static void ecm_ipa_packet_receive_notify
skb->protocol = eth_type_trans(skb, ecm_ipa_ctx->net);
result = netif_rx(skb);
- if (result)
+ if (unlikely(result))
ECM_IPA_ERROR("fail on netif_rx\n");
ecm_ipa_ctx->net->stats.rx_packets++;
ecm_ipa_ctx->net->stats.rx_bytes += packet_len;
@@ -1129,12 +1129,12 @@ static void ecm_ipa_tx_complete_notify
struct sk_buff *skb = (struct sk_buff *)data;
struct ecm_ipa_dev *ecm_ipa_ctx = priv;
- if (!skb) {
+ if (unlikely(!skb)) {
ECM_IPA_ERROR("Bad SKB received from IPA driver\n");
return;
}
- if (!ecm_ipa_ctx) {
+ if (unlikely(!ecm_ipa_ctx)) {
ECM_IPA_ERROR("ecm_ipa_ctx is NULL pointer\n");
return;
}
@@ -1144,7 +1144,7 @@ static void ecm_ipa_tx_complete_notify
skb->len, skb->protocol,
atomic_read(&ecm_ipa_ctx->outstanding_pkts));
- if (evt != IPA_WRITE_DONE) {
+ if (unlikely(evt != IPA_WRITE_DONE)) {
ECM_IPA_ERROR("unsupported event on Tx callback\n");
return;
}
diff --git a/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c b/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c
index efdf97b..c74bbe1 100644
--- a/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c
+++ b/drivers/platform/msm/ipa/ipa_clients/odu_bridge.c
@@ -800,7 +800,7 @@ int odu_bridge_tx_dp(struct sk_buff *skb, struct ipa_tx_meta *metadata)
case ODU_BRIDGE_MODE_ROUTER:
/* Router mode - pass skb to IPA */
res = ipa_tx_dp(IPA_CLIENT_ODU_PROD, skb, metadata);
- if (res) {
+ if (unlikely(res)) {
ODU_BRIDGE_DBG("tx dp failed %d\n", res);
goto out;
}
@@ -813,7 +813,7 @@ int odu_bridge_tx_dp(struct sk_buff *skb, struct ipa_tx_meta *metadata)
ODU_BRIDGE_IS_QMI_ADDR(ipv6hdr->daddr)) {
ODU_BRIDGE_DBG_LOW("QMI packet\n");
skb_copied = skb_clone(skb, GFP_KERNEL);
- if (!skb_copied) {
+ if (unlikely(!skb_copied)) {
ODU_BRIDGE_ERR("No memory\n");
return -ENOMEM;
}
@@ -834,13 +834,13 @@ int odu_bridge_tx_dp(struct sk_buff *skb, struct ipa_tx_meta *metadata)
ODU_BRIDGE_DBG_LOW(
"Multicast pkt, send to APPS and IPA\n");
skb_copied = skb_clone(skb, GFP_KERNEL);
- if (!skb_copied) {
+ if (unlikely(!skb_copied)) {
ODU_BRIDGE_ERR("No memory\n");
return -ENOMEM;
}
res = ipa_tx_dp(IPA_CLIENT_ODU_PROD, skb, metadata);
- if (res) {
+ if (unlikely(res)) {
ODU_BRIDGE_DBG("tx dp failed %d\n", res);
dev_kfree_skb(skb_copied);
goto out;
@@ -855,7 +855,7 @@ int odu_bridge_tx_dp(struct sk_buff *skb, struct ipa_tx_meta *metadata)
}
res = ipa_tx_dp(IPA_CLIENT_ODU_PROD, skb, metadata);
- if (res) {
+ if (unlikely(res)) {
ODU_BRIDGE_DBG("tx dp failed %d\n", res);
goto out;
}
diff --git a/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c
index fd2eab5..3c2f3acf 100644
--- a/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c
@@ -940,7 +940,7 @@ static netdev_tx_t rndis_ipa_start_xmit(struct sk_buff *skb,
}
ret = ipa_pm_activate(rndis_ipa_ctx->pm_hdl);
- if (ret) {
+ if (unlikely(ret)) {
RNDIS_IPA_DEBUG("Failed activate PM client\n");
netif_stop_queue(net);
goto fail_pm_activate;
@@ -959,7 +959,7 @@ static netdev_tx_t rndis_ipa_start_xmit(struct sk_buff *skb,
skb = rndis_encapsulate_skb(skb, rndis_ipa_ctx);
trace_rndis_tx_dp(skb->protocol);
ret = ipa_tx_dp(IPA_TO_USB_CLIENT, skb, NULL);
- if (ret) {
+ if (unlikely(ret)) {
RNDIS_IPA_ERROR("ipa transmit failed (%d)\n", ret);
goto fail_tx_packet;
}
@@ -1006,7 +1006,7 @@ static void rndis_ipa_tx_complete_notify(
ret = 0;
NULL_CHECK_RETVAL(private);
- if (ret)
+ if (unlikely(ret))
return;
trace_rndis_status_rcvd(skb->protocol);
@@ -1120,7 +1120,7 @@ static void rndis_ipa_packet_receive_notify(
return;
}
- if (evt != IPA_RECEIVE) {
+ if (unlikely(evt != IPA_RECEIVE)) {
RNDIS_IPA_ERROR("a none IPA_RECEIVE event in driver RX\n");
return;
}
@@ -1140,7 +1140,7 @@ static void rndis_ipa_packet_receive_notify(
trace_rndis_netif_ni(skb->protocol);
result = netif_rx_ni(skb);
- if (result)
+ if (unlikely(result))
RNDIS_IPA_ERROR("fail on netif_rx_ni\n");
rndis_ipa_ctx->net->stats.rx_packets++;
rndis_ipa_ctx->net->stats.rx_bytes += packet_len;
@@ -1817,7 +1817,7 @@ static struct sk_buff *rndis_encapsulate_skb(struct sk_buff *skb,
if (unlikely(skb_headroom(skb) < sizeof(rndis_template_hdr))) {
struct sk_buff *new_skb = skb_copy_expand(skb,
sizeof(rndis_template_hdr), 0, GFP_ATOMIC);
- if (!new_skb) {
+ if (unlikely(!new_skb)) {
RNDIS_IPA_ERROR("no memory for skb expand\n");
return skb;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 77c0f2a..7bc80ac 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -55,6 +55,8 @@
#include "ipa_trace.h"
#include "ipa_odl.h"
+#define IPA_SUSPEND_BUSY_TIMEOUT (msecs_to_jiffies(10))
+
/*
* The following for adding code (ie. for EMULATION) not found on x86.
*/
@@ -118,7 +120,7 @@ static void ipa3_load_ipa_fw(struct work_struct *work);
static DECLARE_WORK(ipa3_fw_loading_work, ipa3_load_ipa_fw);
static void ipa_dec_clients_disable_clks_on_wq(struct work_struct *work);
-static DECLARE_WORK(ipa_dec_clients_disable_clks_on_wq_work,
+static DECLARE_DELAYED_WORK(ipa_dec_clients_disable_clks_on_wq_work,
ipa_dec_clients_disable_clks_on_wq);
static int ipa3_ioctl_add_rt_rule_v2(unsigned long arg);
@@ -4811,8 +4813,16 @@ static void __ipa3_dec_client_disable_clks(void)
ret = atomic_sub_return(1, &ipa3_ctx->ipa3_active_clients.cnt);
if (ret > 0)
goto unlock_mutex;
- ipa3_suspend_apps_pipes(true);
- ipa3_disable_clks();
+ ret = ipa3_suspend_apps_pipes(true);
+ if (ret) {
+ /* HW is busy, retry after some time */
+ atomic_inc(&ipa3_ctx->ipa3_active_clients.cnt);
+ queue_delayed_work(ipa3_ctx->power_mgmt_wq,
+ &ipa_dec_clients_disable_clks_on_wq_work,
+ IPA_SUSPEND_BUSY_TIMEOUT);
+ } else {
+ ipa3_disable_clks();
+ }
unlock_mutex:
mutex_unlock(&ipa3_ctx->ipa3_active_clients.mutex);
@@ -4865,8 +4875,8 @@ void ipa3_dec_client_disable_clks_no_block(
}
/* seems like this is the only client holding the clocks */
- queue_work(ipa3_ctx->power_mgmt_wq,
- &ipa_dec_clients_disable_clks_on_wq_work);
+ queue_delayed_work(ipa3_ctx->power_mgmt_wq,
+ &ipa_dec_clients_disable_clks_on_wq_work, 0);
}
/**
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 5bebb15..d0ee749 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -236,6 +236,10 @@ static void ipa3_send_nop_desc(struct work_struct *work)
struct ipa3_tx_pkt_wrapper *tx_pkt;
IPADBG_LOW("gsi send NOP for ch: %lu\n", sys->ep->gsi_chan_hdl);
+
+ if (atomic_read(&sys->workqueue_flushed))
+ return;
+
tx_pkt = kmem_cache_zalloc(ipa3_ctx->tx_pkt_wrapper_cache, GFP_KERNEL);
if (!tx_pkt) {
queue_work(sys->wq, &sys->work);
@@ -344,7 +348,7 @@ int ipa3_send(struct ipa3_sys_context *sys,
for (i = 0; i < num_desc; i++) {
tx_pkt = kmem_cache_zalloc(ipa3_ctx->tx_pkt_wrapper_cache,
GFP_ATOMIC);
- if (!tx_pkt) {
+ if (unlikely(!tx_pkt)) {
IPAERR("failed to alloc tx wrapper\n");
result = -ENOMEM;
goto failure;
@@ -358,8 +362,8 @@ int ipa3_send(struct ipa3_sys_context *sys,
/* populate tag field */
if (desc[i].is_tag_status) {
- if (ipa_populate_tag_field(&desc[i], tx_pkt,
- &tag_pyld_ret)) {
+ if (unlikely(ipa_populate_tag_field(&desc[i], tx_pkt,
+ &tag_pyld_ret))) {
IPAERR("Failed to populate tag field\n");
result = -EFAULT;
goto failure_dma_map;
@@ -399,7 +403,8 @@ int ipa3_send(struct ipa3_sys_context *sys,
tx_pkt->no_unmap_dma = true;
}
}
- if (dma_mapping_error(ipa3_ctx->pdev, tx_pkt->mem.phys_base)) {
+ if (unlikely(dma_mapping_error(ipa3_ctx->pdev,
+ tx_pkt->mem.phys_base))) {
IPAERR("failed to do dma map.\n");
result = -EFAULT;
goto failure_dma_map;
@@ -450,7 +455,7 @@ int ipa3_send(struct ipa3_sys_context *sys,
IPADBG_LOW("ch:%lu queue xfer\n", sys->ep->gsi_chan_hdl);
result = gsi_queue_xfer(sys->ep->gsi_chan_hdl, num_desc,
gsi_xfer, true);
- if (result != GSI_STATUS_SUCCESS) {
+ if (unlikely(result != GSI_STATUS_SUCCESS)) {
IPAERR_RL("GSI xfer failed.\n");
result = -EFAULT;
goto failure;
@@ -466,6 +471,7 @@ int ipa3_send(struct ipa3_sys_context *sys,
/* set the timer for sending the NOP descriptor */
if (send_nop) {
+
ktime_t time = ktime_set(0, IPA_TX_SEND_COMPL_NOP_DELAY_NS);
IPADBG_LOW("scheduling timer for ch %lu\n",
@@ -1268,6 +1274,8 @@ int ipa3_teardown_sys_pipe(u32 clnt_hdl)
if (IPA_CLIENT_IS_CONS(ep->client))
cancel_delayed_work_sync(&ep->sys->replenish_rx_work);
flush_workqueue(ep->sys->wq);
+ if (IPA_CLIENT_IS_PROD(ep->client))
+ atomic_set(&ep->sys->workqueue_flushed, 1);
/* tear down the default pipe before we reset the channel*/
if (ep->client == IPA_CLIENT_APPS_WAN_COAL_CONS) {
@@ -1490,7 +1498,7 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
return -EINVAL;
}
- if (skb->len == 0) {
+ if (unlikely(skb->len == 0)) {
IPAERR("packet size is 0\n");
return -EINVAL;
}
@@ -1506,7 +1514,7 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
*/
if (IPA_CLIENT_IS_CONS(dst)) {
src_ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_APPS_LAN_PROD);
- if (-1 == src_ep_idx) {
+ if (unlikely(-1 == src_ep_idx)) {
IPAERR("Client %u is not mapped\n",
IPA_CLIENT_APPS_LAN_PROD);
goto fail_gen;
@@ -1514,7 +1522,7 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
dst_ep_idx = ipa3_get_ep_mapping(dst);
} else {
src_ep_idx = ipa3_get_ep_mapping(dst);
- if (-1 == src_ep_idx) {
+ if (unlikely(-1 == src_ep_idx)) {
IPAERR("Client %u is not mapped\n", dst);
goto fail_gen;
}
@@ -1526,7 +1534,7 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
sys = ipa3_ctx->ep[src_ep_idx].sys;
- if (!sys || !sys->ep->valid) {
+ if (unlikely(!sys || !sys->ep->valid)) {
IPAERR_RL("pipe %d not valid\n", src_ep_idx);
goto fail_pipe_not_valid;
}
@@ -1547,7 +1555,7 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
gsi_ep->prefetch_mode == GSI_FREE_PRE_FETCH)
max_desc -= gsi_ep->prefetch_threshold;
if (num_frags + 3 > max_desc) {
- if (skb_linearize(skb)) {
+ if (unlikely(skb_linearize(skb))) {
IPAERR("Failed to linear skb with %d frags\n",
num_frags);
goto fail_gen;
@@ -1561,7 +1569,7 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
* 1 desc for each frag
*/
desc = kzalloc(sizeof(*desc) * (num_frags + 3), GFP_ATOMIC);
- if (!desc) {
+ if (unlikely(!desc)) {
IPAERR("failed to alloc desc array\n");
goto fail_gen;
}
@@ -1623,7 +1631,8 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
desc[skb_idx].callback = NULL;
}
- if (ipa3_send(sys, num_frags + data_idx, desc, true)) {
+ if (unlikely(ipa3_send(sys, num_frags + data_idx,
+ desc, true))) {
IPAERR_RL("fail to send skb %pK num_frags %u SWP\n",
skb, num_frags);
goto fail_send;
@@ -1654,7 +1663,8 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
desc[data_idx].dma_address = meta->dma_address;
}
if (num_frags == 0) {
- if (ipa3_send(sys, data_idx + 1, desc, true)) {
+ if (unlikely(ipa3_send(sys, data_idx + 1,
+ desc, true))) {
IPAERR("fail to send skb %pK HWP\n", skb);
goto fail_mem;
}
@@ -1673,8 +1683,8 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
desc[data_idx+f].user2 = desc[data_idx].user2;
desc[data_idx].callback = NULL;
- if (ipa3_send(sys, num_frags + data_idx + 1,
- desc, true)) {
+ if (unlikely(ipa3_send(sys, num_frags + data_idx + 1,
+ desc, true))) {
IPAERR("fail to send skb %pK num_frags %u\n",
skb, num_frags);
goto fail_mem;
@@ -1729,26 +1739,27 @@ static void ipa3_wq_repl_rx(struct work_struct *work)
begin:
while (1) {
next = (curr + 1) % sys->repl->capacity;
- if (next == atomic_read(&sys->repl->head_idx))
+ if (unlikely(next == atomic_read(&sys->repl->head_idx)))
goto fail_kmem_cache_alloc;
rx_pkt = kmem_cache_zalloc(ipa3_ctx->rx_pkt_wrapper_cache,
flag);
- if (!rx_pkt)
+ if (unlikely(!rx_pkt))
goto fail_kmem_cache_alloc;
INIT_WORK(&rx_pkt->work, ipa3_wq_rx_avail);
rx_pkt->sys = sys;
rx_pkt->data.skb = sys->get_skb(sys->rx_buff_sz, flag);
- if (rx_pkt->data.skb == NULL)
+ if (unlikely(rx_pkt->data.skb == NULL))
goto fail_skb_alloc;
ptr = skb_put(rx_pkt->data.skb, sys->rx_buff_sz);
rx_pkt->data.dma_addr = dma_map_single(ipa3_ctx->pdev, ptr,
sys->rx_buff_sz,
DMA_FROM_DEVICE);
- if (dma_mapping_error(ipa3_ctx->pdev, rx_pkt->data.dma_addr)) {
+ if (unlikely(dma_mapping_error(ipa3_ctx->pdev,
+ rx_pkt->data.dma_addr))) {
pr_err_ratelimited("%s dma map fail %pK for %pK sys=%pK\n",
__func__, (void *)rx_pkt->data.dma_addr,
ptr, sys);
@@ -1802,8 +1813,8 @@ static struct ipa3_rx_pkt_wrapper *ipa3_alloc_rx_pkt_page(
rx_pkt->page_data.dma_addr = dma_map_page(ipa3_ctx->pdev,
rx_pkt->page_data.page, 0,
rx_pkt->len, DMA_FROM_DEVICE);
- if (dma_mapping_error(ipa3_ctx->pdev,
- rx_pkt->page_data.dma_addr)) {
+ if (unlikely(dma_mapping_error(ipa3_ctx->pdev,
+ rx_pkt->page_data.dma_addr))) {
pr_err_ratelimited("%s dma map fail %pK for %pK\n",
__func__, (void *)rx_pkt->page_data.dma_addr,
rx_pkt->page_data.page);
@@ -1829,7 +1840,7 @@ static void ipa3_replenish_rx_page_cache(struct ipa3_sys_context *sys)
for (curr = 0; curr < sys->repl->capacity; curr++) {
rx_pkt = ipa3_alloc_rx_pkt_page(GFP_KERNEL, false);
- if (!rx_pkt) {
+ if (unlikely(!rx_pkt)) {
IPAERR("ipa3_alloc_rx_pkt_page fails\n");
ipa_assert();
break;
@@ -1877,7 +1888,7 @@ static void ipa3_replenish_rx_page_recycle(struct ipa3_sys_context *sys)
rx_pkt = ipa3_alloc_rx_pkt_page(flag, true);
if (!rx_pkt && flag == GFP_ATOMIC)
break;
- else if (!rx_pkt)
+ else if (unlikely(!rx_pkt))
goto fail_kmem_cache_alloc;
rx_pkt->sys = sys;
}
@@ -1901,7 +1912,7 @@ static void ipa3_replenish_rx_page_recycle(struct ipa3_sys_context *sys)
if (idx == IPA_REPL_XFER_MAX) {
ret = gsi_queue_xfer(sys->ep->gsi_chan_hdl, idx,
gsi_xfer_elem_array, false);
- if (ret != GSI_STATUS_SUCCESS) {
+ if (unlikely(ret != GSI_STATUS_SUCCESS)) {
/* we don't expect this will happen */
IPAERR("failed to provide buffer: %d\n", ret);
ipa_assert();
@@ -1913,7 +1924,7 @@ static void ipa3_replenish_rx_page_recycle(struct ipa3_sys_context *sys)
/* only ring doorbell once here */
ret = gsi_queue_xfer(sys->ep->gsi_chan_hdl, idx,
gsi_xfer_elem_array, true);
- if (ret == GSI_STATUS_SUCCESS) {
+ if (likely(ret == GSI_STATUS_SUCCESS)) {
/* ensure write is done before setting head index */
mb();
atomic_set(&sys->repl->head_idx, curr);
@@ -1971,7 +1982,7 @@ static void ipa3_replenish_wlan_rx_cache(struct ipa3_sys_context *sys)
ret = gsi_queue_xfer(sys->ep->gsi_chan_hdl, 1,
&gsi_xfer_elem_one, true);
- if (ret) {
+ if (unlikely(ret)) {
IPAERR("failed to provide buffer: %d\n", ret);
goto fail_provide_rx_buffer;
}
@@ -2435,12 +2446,19 @@ static void free_rx_page(void *chan_user_data, void *xfer_user_data)
{
struct ipa3_rx_pkt_wrapper *rx_pkt = (struct ipa3_rx_pkt_wrapper *)
xfer_user_data;
+ struct ipa3_sys_context *sys = rx_pkt->sys;
+ int i;
+ for (i = 0; i < sys->repl->capacity; i++)
+ if (sys->repl->cache[i] == rx_pkt)
+ break;
dma_unmap_page(ipa3_ctx->pdev, rx_pkt->page_data.dma_addr,
rx_pkt->len, DMA_FROM_DEVICE);
__free_pages(rx_pkt->page_data.page,
IPA_WAN_PAGE_ORDER);
kmem_cache_free(ipa3_ctx->rx_pkt_wrapper_cache, rx_pkt);
+ if (i < sys->repl->capacity)
+ sys->repl->cache[i] = NULL;
}
/**
@@ -2489,14 +2507,17 @@ static void ipa3_cleanup_rx(struct ipa3_sys_context *sys)
} else {
for (i = 0; i < sys->repl->capacity; i++) {
rx_pkt = sys->repl->cache[i];
- dma_unmap_page(ipa3_ctx->pdev,
- rx_pkt->page_data.dma_addr,
- rx_pkt->len,
- DMA_FROM_DEVICE);
- __free_pages(rx_pkt->page_data.page,
- IPA_WAN_PAGE_ORDER);
- kmem_cache_free(ipa3_ctx->rx_pkt_wrapper_cache,
- rx_pkt);
+ if (rx_pkt) {
+ dma_unmap_page(ipa3_ctx->pdev,
+ rx_pkt->page_data.dma_addr,
+ rx_pkt->len,
+ DMA_FROM_DEVICE);
+ __free_pages(rx_pkt->page_data.page,
+ IPA_WAN_PAGE_ORDER);
+ kmem_cache_free(
+ ipa3_ctx->rx_pkt_wrapper_cache,
+ rx_pkt);
+ }
}
}
kfree(sys->repl->cache);
@@ -3124,14 +3145,14 @@ static struct sk_buff *handle_skb_completion(struct gsi_chan_xfer_notify
rx_skb->truesize = rx_pkt->len + sizeof(struct sk_buff);
}
- if (notify->veid >= GSI_VEID_MAX) {
+ if (unlikely(notify->veid >= GSI_VEID_MAX)) {
WARN_ON(1);
return NULL;
}
/*Assesrt when WAN consumer channel receive EOB event*/
- if (notify->evt_id == GSI_CHAN_EVT_EOB &&
- sys->ep->client == IPA_CLIENT_APPS_WAN_CONS) {
+ if (unlikely(notify->evt_id == GSI_CHAN_EVT_EOB &&
+ sys->ep->client == IPA_CLIENT_APPS_WAN_CONS)) {
IPAERR("EOB event received on WAN consumer channel\n");
ipa_assert();
}
@@ -3255,13 +3276,13 @@ static void ipa3_wq_rx_common(struct ipa3_sys_context *sys,
struct ipa3_sys_context *coal_sys;
int ipa_ep_idx;
- if (!notify) {
+ if (unlikely(!notify)) {
IPAERR_RL("gsi_chan_xfer_notify is null\n");
return;
}
rx_skb = handle_skb_completion(notify, true);
- if (rx_skb) {
+ if (likely(rx_skb)) {
sys->pyld_hdlr(rx_skb, sys);
/* For coalescing, we have 2 transfer rings to replenish */
@@ -3269,7 +3290,7 @@ static void ipa3_wq_rx_common(struct ipa3_sys_context *sys,
ipa_ep_idx = ipa3_get_ep_mapping(
IPA_CLIENT_APPS_WAN_CONS);
- if (ipa_ep_idx == IPA_EP_NOT_ALLOCATED) {
+ if (unlikely(ipa_ep_idx == IPA_EP_NOT_ALLOCATED)) {
IPAERR("Invalid client.\n");
return;
}
@@ -3329,8 +3350,8 @@ static void ipa3_rx_napi_chain(struct ipa3_sys_context *sys,
*/
ipa_ep_idx = ipa3_get_ep_mapping(
IPA_CLIENT_APPS_WAN_CONS);
- if (ipa_ep_idx ==
- IPA_EP_NOT_ALLOCATED) {
+ if (unlikely(ipa_ep_idx ==
+ IPA_EP_NOT_ALLOCATED)) {
IPAERR("Invalid client.\n");
return;
}
@@ -3366,8 +3387,8 @@ static void ipa3_rx_napi_chain(struct ipa3_sys_context *sys,
*/
ipa_ep_idx = ipa3_get_ep_mapping(
IPA_CLIENT_APPS_WAN_CONS);
- if (ipa_ep_idx ==
- IPA_EP_NOT_ALLOCATED) {
+ if (unlikely(ipa_ep_idx ==
+ IPA_EP_NOT_ALLOCATED)) {
IPAERR("Invalid client.\n");
return;
}
@@ -3504,6 +3525,7 @@ static int ipa3_assign_policy(struct ipa_sys_connect_params *in,
sys->policy = IPA_POLICY_INTR_MODE;
sys->use_comm_evt_ring = true;
INIT_WORK(&sys->work, ipa3_send_nop_desc);
+ atomic_set(&sys->workqueue_flushed, 0);
/*
* enable source notification status for exception packets
@@ -3533,6 +3555,7 @@ static int ipa3_assign_policy(struct ipa_sys_connect_params *in,
sys->policy = IPA_POLICY_INTR_MODE;
sys->use_comm_evt_ring = true;
INIT_WORK(&sys->work, ipa3_send_nop_desc);
+ atomic_set(&sys->workqueue_flushed, 0);
}
} else {
if (in->client == IPA_CLIENT_APPS_LAN_CONS ||
@@ -4155,7 +4178,7 @@ static void ipa_gsi_irq_rx_notify_cb(struct gsi_chan_xfer_notify *notify)
{
struct ipa3_sys_context *sys;
- if (!notify) {
+ if (unlikely(!notify)) {
IPAERR("gsi notify is NULL.\n");
return;
}
@@ -4187,7 +4210,7 @@ static void ipa_dma_gsi_irq_rx_notify_cb(struct gsi_chan_xfer_notify *notify)
{
struct ipa3_sys_context *sys;
- if (!notify) {
+ if (unlikely(!notify)) {
IPAERR("gsi notify is NULL.\n");
return;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 7bfe159..58c924f 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -975,6 +975,7 @@ struct ipa3_repl_ctx {
struct ipa3_sys_context {
u32 len;
atomic_t curr_polling_state;
+ atomic_t workqueue_flushed;
struct delayed_work switch_to_intr_work;
enum ipa3_sys_pipe_policy policy;
bool use_comm_evt_ring;
@@ -2914,7 +2915,7 @@ int ipa3_create_wdi_mapping(u32 num_buffers, struct ipa_wdi_buffer_info *info);
int ipa3_set_flt_tuple_mask(int pipe_idx, struct ipahal_reg_hash_tuple *tuple);
int ipa3_set_rt_tuple_mask(int tbl_idx, struct ipahal_reg_hash_tuple *tuple);
void ipa3_set_resorce_groups_min_max_limits(void);
-void ipa3_suspend_apps_pipes(bool suspend);
+int ipa3_suspend_apps_pipes(bool suspend);
int ipa3_flt_read_tbl_from_hw(u32 pipe_idx,
enum ipa_ip_type ip_type,
bool hashable,
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mpm.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mpm.c
index 80a3e2a..22f82bd 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_mpm.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mpm.c
@@ -70,7 +70,7 @@
#define IPA_POLL_FOR_EMPTINESS_SLEEP_USEC 20
#define IPA_CHANNEL_STOP_IN_PROC_TO_MSEC 5
#define IPA_CHANNEL_STOP_IN_PROC_SLEEP_USEC 200
-
+#define IPA_MHIP_HOLB_TMO 31 /* value to match granularity on ipa HW 4.5 */
enum mhip_re_type {
MHIP_RE_XFER = 0x2,
MHIP_RE_NOP = 0x4,
@@ -424,8 +424,6 @@ static void ipa_mpm_change_teth_state(int probe_id,
static void ipa_mpm_change_gsi_state(int probe_id,
enum ipa_mpm_mhip_chan mhip_chan,
enum ipa_mpm_gsi_state next_state);
-static int ipa_mpm_start_stop_ul_mhip_data_path(int probe_id,
- enum ipa_mpm_start_stop_type start);
static int ipa_mpm_probe(struct platform_device *pdev);
static int ipa_mpm_vote_unvote_pcie_clk(enum ipa_mpm_clk_vote_type vote,
int probe_id);
@@ -435,6 +433,7 @@ static enum mhip_status_type ipa_mpm_start_stop_mhip_chan(
enum ipa_mpm_mhip_chan mhip_chan,
int probe_id,
enum ipa_mpm_start_stop_type start_stop);
+static int ipa_mpm_start_mhip_holb_tmo(u32 clnt_hdl);
static struct mhi_driver mhi_driver = {
.id_table = mhi_driver_match_table,
@@ -500,6 +499,17 @@ static int ipa_mpm_set_dma_mode(enum ipa_client_type src_pipe,
return result;
}
+static int ipa_mpm_start_mhip_holb_tmo(u32 clnt_hdl)
+{
+ struct ipa_ep_cfg_holb holb_cfg;
+
+ memset(&holb_cfg, 0, sizeof(holb_cfg));
+ holb_cfg.en = IPA_HOLB_TMR_EN;
+ /* 31 ms timer, which is less than tag timeout */
+ holb_cfg.tmr_val = IPA_MHIP_HOLB_TMO;
+ return ipa3_cfg_ep_holb(clnt_hdl, &holb_cfg);
+}
+
/**
* ipa_mpm_smmu_map() - SMMU maps ring and the buffer pointer.
* @va_addr: virtual address that needs to be mapped
@@ -1034,6 +1044,21 @@ static int ipa_mpm_connect_mhip_gsi_pipe(enum ipa_client_type mhip_client,
goto fail_alloc_channel;
}
+ if (IPA_CLIENT_IS_CONS(mhip_client)) {
+ /*
+ * Enable HOLB timer one time after bootup/SSR.
+ * The HOLB timeout drops the packets on MHIP if
+ * there is a stall on MHIP TX pipe greater than
+ * configured timeout.
+ */
+ result = ipa_mpm_start_mhip_holb_tmo(ipa_ep_idx);
+ if (result) {
+ IPA_MPM_ERR("HOLB config failed for %d, fail = %d\n",
+ ipa_ep_idx, result);
+ goto fail_alloc_channel;
+ }
+ }
+
if (IPA_CLIENT_IS_PROD(mhip_client))
ipa_mpm_change_gsi_state(mhi_idx,
IPA_MPM_MHIP_CHAN_DL,
@@ -1326,11 +1351,9 @@ static void ipa_mpm_mhip_shutdown(int mhip_idx)
get_ipa3_client(mhip_idx, &ul_prod_chan, &dl_cons_chan);
- if (mhip_idx != IPA_MPM_MHIP_CH_ID_2) {
+ if (mhip_idx != IPA_MPM_MHIP_CH_ID_2)
/* For DPL, stop only DL channel */
- ipa_mpm_start_stop_ul_mhip_data_path(mhip_idx, MPM_MHIP_STOP);
ipa_mpm_clean_mhip_chan(mhip_idx, ul_prod_chan);
- }
ipa_mpm_clean_mhip_chan(mhip_idx, dl_cons_chan);
@@ -1713,13 +1736,6 @@ int ipa_mpm_notify_wan_state(struct wan_ioctl_notify_wan_state *state)
case MHIP_STATUS_SUCCESS:
ipa_mpm_ctx->md[probe_id].teth_state =
IPA_MPM_TETH_CONNECTED;
- ret = ipa_mpm_start_stop_ul_mhip_data_path(
- probe_id, MPM_MHIP_START);
- if (ret) {
- IPA_MPM_ERR("UL chan start err = %d\n", ret);
- ipa_mpm_vote_unvote_pcie_clk(CLK_OFF, probe_id);
- return ret;
- }
break;
case MHIP_STATUS_EP_NOT_READY:
case MHIP_STATUS_NO_OP:
@@ -1767,8 +1783,6 @@ int ipa_mpm_notify_wan_state(struct wan_ioctl_notify_wan_state *state)
switch (status) {
case MHIP_STATUS_SUCCESS:
ipa_mpm_change_teth_state(probe_id, IPA_MPM_TETH_INIT);
- ipa_mpm_start_stop_ul_mhip_data_path(probe_id,
- MPM_MHIP_STOP);
break;
case MHIP_STATUS_NO_OP:
case MHIP_STATUS_EP_NOT_READY:
@@ -1881,64 +1895,6 @@ static void ipa_mpm_read_channel(enum ipa_client_type chan)
IPA_MPM_ERR("Reading of channel failed for ep %d\n", ep);
}
-static int ipa_mpm_start_stop_ul_mhip_data_path(int probe_id,
- enum ipa_mpm_start_stop_type start)
-{
- int ipa_ep_idx;
- int res = 0;
- enum ipa_client_type ul_chan, dl_chan;
-
- if (probe_id >= IPA_MPM_MHIP_CH_ID_MAX) {
- IPA_MPM_ERR("Unknown probe_id\n");
- return 0;
- }
- get_ipa3_client(probe_id, &ul_chan, &dl_chan);
- IPA_MPM_DBG("Start/Stop Data Path ? = %d\n", start);
-
-
- /* MHIP Start Data path:
- * IPA MHIP Producer: remove HOLB
- * IPA MHIP Consumer : no op as there is no delay on these pipes.
- */
- if (start) {
- IPA_MPM_DBG("Enabling data path\n");
- if (ul_chan != IPA_CLIENT_MAX) {
- /* Remove HOLB on the producer pipe */
- IPA_MPM_DBG("Removing HOLB on ep = %s\n",
- __stringify(ul_chan));
- ipa_ep_idx = ipa3_get_ep_mapping(ul_chan);
-
- if (ipa_ep_idx == IPA_EP_NOT_ALLOCATED) {
- IPAERR("failed to get idx");
- return ipa_ep_idx;
- }
-
- res = ipa3_enable_data_path(ipa_ep_idx);
- if (res)
- IPA_MPM_ERR("Enable data path failed res=%d\n",
- res);
- }
- } else {
- IPA_MPM_DBG("Disabling data path\n");
- if (ul_chan != IPA_CLIENT_MAX) {
- /* Set HOLB on the producer pipe */
- ipa_ep_idx = ipa3_get_ep_mapping(ul_chan);
-
- if (ipa_ep_idx == IPA_EP_NOT_ALLOCATED) {
- IPAERR("failed to get idx");
- return ipa_ep_idx;
- }
-
- res = ipa3_disable_data_path(ipa_ep_idx);
- if (res)
- IPA_MPM_ERR("disable data path failed res=%d\n",
- res);
- }
- }
-
- return res;
-}
-
/* ipa_mpm_mhi_probe_cb is received for each MHI'/MHI channel
* Currently we have 4 MHI channels.
*/
@@ -2294,12 +2250,6 @@ static int ipa_mpm_mhi_probe_cb(struct mhi_device *mhi_dev,
/* No teth started yet, disable UL channel */
ipa_mpm_start_stop_mhip_chan(IPA_MPM_MHIP_CHAN_UL,
probe_id, MPM_MHIP_STOP);
- /* Disable data path */
- if (ipa_mpm_start_stop_ul_mhip_data_path(probe_id,
- MPM_MHIP_STOP)) {
- IPA_MPM_ERR("MHIP Enable data path failed\n");
- goto fail_start_channel;
- }
}
ipa_mpm_vote_unvote_pcie_clk(CLK_OFF, probe_id);
break;
@@ -2308,14 +2258,6 @@ static int ipa_mpm_mhi_probe_cb(struct mhi_device *mhi_dev,
IPA_MPM_DBG("UL channel is already started, continue\n");
ipa_mpm_change_teth_state(probe_id, IPA_MPM_TETH_CONNECTED);
- /* Enable data path */
- if (ul_prod != IPA_CLIENT_MAX) {
- if (ipa_mpm_start_stop_ul_mhip_data_path(probe_id,
- MPM_MHIP_START)) {
- IPA_MPM_ERR("MHIP Enable data path failed\n");
- goto fail_start_channel;
- }
- }
/* Lift the delay for rmnet USB prod pipe */
if (probe_id == IPA_MPM_MHIP_CH_ID_1) {
pipe_idx = ipa3_get_ep_mapping(IPA_CLIENT_USB_PROD);
@@ -2477,8 +2419,8 @@ static void ipa_mpm_mhi_status_cb(struct mhi_device *mhi_dev,
case MHI_CB_PENDING_DATA:
case MHI_CB_SYS_ERROR:
case MHI_CB_FATAL_ERROR:
- case MHI_CB_BW_REQ:
case MHI_CB_EE_MISSION_MODE:
+ case MHI_CB_DTR_SIGNAL:
IPA_MPM_ERR("unexpected event %d\n", mhi_cb);
break;
}
@@ -2596,8 +2538,6 @@ int ipa_mpm_mhip_xdci_pipe_enable(enum ipa_usb_teth_prot xdci_teth_prot)
case MHIP_STATUS_SUCCESS:
case MHIP_STATUS_NO_OP:
ipa_mpm_change_teth_state(probe_id, IPA_MPM_TETH_CONNECTED);
- ipa_mpm_start_stop_ul_mhip_data_path(probe_id,
- MPM_MHIP_START);
pipe_idx = ipa3_get_ep_mapping(IPA_CLIENT_USB_PROD);
@@ -2717,7 +2657,6 @@ int ipa_mpm_mhip_xdci_pipe_disable(enum ipa_usb_teth_prot xdci_teth_prot)
case MHIP_STATUS_NO_OP:
case MHIP_STATUS_EP_NOT_READY:
ipa_mpm_change_teth_state(probe_id, IPA_MPM_TETH_INIT);
- ipa_mpm_start_stop_ul_mhip_data_path(probe_id, MPM_MHIP_STOP);
break;
case MHIP_STATUS_FAIL:
case MHIP_STATUS_BAD_STATE:
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c
index c73f32c..f35abd0 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c
@@ -971,12 +971,13 @@ static int ipa_pm_activate_helper(struct ipa_pm_client *client, bool sync)
*/
int ipa_pm_activate(u32 hdl)
{
- if (ipa_pm_ctx == NULL) {
+ if (unlikely(ipa_pm_ctx == NULL)) {
IPA_PM_ERR("PM_ctx is null\n");
return -EINVAL;
}
- if (hdl >= IPA_PM_MAX_CLIENTS || ipa_pm_ctx->clients[hdl] == NULL) {
+ if (unlikely(hdl >= IPA_PM_MAX_CLIENTS ||
+ ipa_pm_ctx->clients[hdl] == NULL)) {
IPA_PM_ERR("Invalid Param\n");
return -EINVAL;
}
@@ -993,12 +994,13 @@ int ipa_pm_activate(u32 hdl)
*/
int ipa_pm_activate_sync(u32 hdl)
{
- if (ipa_pm_ctx == NULL) {
+ if (unlikely(ipa_pm_ctx == NULL)) {
IPA_PM_ERR("PM_ctx is null\n");
return -EINVAL;
}
- if (hdl >= IPA_PM_MAX_CLIENTS || ipa_pm_ctx->clients[hdl] == NULL) {
+ if (unlikely(hdl >= IPA_PM_MAX_CLIENTS ||
+ ipa_pm_ctx->clients[hdl] == NULL)) {
IPA_PM_ERR("Invalid Param\n");
return -EINVAL;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index 197e99b..0857ad0 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -39,7 +39,7 @@
#define IPA_V4_0_CLK_RATE_NOMINAL (220 * 1000 * 1000UL)
#define IPA_V4_0_CLK_RATE_TURBO (250 * 1000 * 1000UL)
-#define IPA_V3_0_MAX_HOLB_TMR_VAL (4294967296 - 1)
+#define IPA_MAX_HOLB_TMR_VAL (4294967296 - 1)
#define IPA_V3_0_BW_THRESHOLD_TURBO_MBPS (1000)
#define IPA_V3_0_BW_THRESHOLD_NOMINAL_MBPS (600)
@@ -4037,18 +4037,18 @@ int ipa3_get_ep_mapping(enum ipa_client_type client)
int ipa_ep_idx;
u8 hw_idx = ipa3_get_hw_type_index();
- if (client >= IPA_CLIENT_MAX || client < 0) {
+ if (unlikely(client >= IPA_CLIENT_MAX || client < 0)) {
IPAERR_RL("Bad client number! client =%d\n", client);
return IPA_EP_NOT_ALLOCATED;
}
- if (!ipa3_ep_mapping[hw_idx][client].valid)
+ if (unlikely(!ipa3_ep_mapping[hw_idx][client].valid))
return IPA_EP_NOT_ALLOCATED;
ipa_ep_idx =
ipa3_ep_mapping[hw_idx][client].ipa_gsi_ep_info.ipa_ep_num;
- if (ipa_ep_idx < 0 || (ipa_ep_idx >= IPA3_MAX_NUM_PIPES
- && client != IPA_CLIENT_DUMMY_CONS))
+ if (unlikely(ipa_ep_idx < 0 || (ipa_ep_idx >= IPA3_MAX_NUM_PIPES
+ && client != IPA_CLIENT_DUMMY_CONS)))
return IPA_EP_NOT_ALLOCATED;
return ipa_ep_idx;
@@ -4066,7 +4066,7 @@ const struct ipa_gsi_ep_config *ipa3_get_gsi_ep_info
int ep_idx;
ep_idx = ipa3_get_ep_mapping(client);
- if (ep_idx == IPA_EP_NOT_ALLOCATED)
+ if (unlikely(ep_idx == IPA_EP_NOT_ALLOCATED))
return NULL;
if (!ipa3_ep_mapping[ipa3_get_hw_type_index()][client].valid)
@@ -5986,6 +5986,7 @@ int ipa3_controller_static_bind(struct ipa3_controller *ctrl,
ctrl->ipa_init_sram = _ipa_init_sram_v3;
ctrl->ipa_sram_read_settings = _ipa_sram_settings_read_v3_0;
ctrl->ipa_init_hdr = _ipa_init_hdr_v3_0;
+ ctrl->max_holb_tmr_val = IPA_MAX_HOLB_TMR_VAL;
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0)
ctrl->ipa3_read_ep_reg = _ipa_read_ep_reg_v4_0;
@@ -7485,12 +7486,10 @@ void ipa3_set_resorce_groups_min_max_limits(void)
IPADBG("EXIT\n");
}
-static void ipa3_gsi_poll_after_suspend(struct ipa3_ep_context *ep)
+static bool ipa3_gsi_channel_is_quite(struct ipa3_ep_context *ep)
{
bool empty;
- IPADBG("switch ch %ld to poll\n", ep->gsi_chan_hdl);
- gsi_config_channel_mode(ep->gsi_chan_hdl, GSI_CHAN_MODE_POLL);
gsi_is_channel_empty(ep->gsi_chan_hdl, &empty);
if (!empty) {
IPADBG("ch %ld not empty\n", ep->gsi_chan_hdl);
@@ -7499,6 +7498,7 @@ static void ipa3_gsi_poll_after_suspend(struct ipa3_ep_context *ep)
if (!atomic_read(&ep->sys->curr_polling_state))
__ipa_gsi_irq_rx_scedule_poll(ep->sys);
}
+ return empty;
}
static int __ipa3_stop_gsi_channel(u32 clnt_hdl)
@@ -7624,141 +7624,78 @@ int ipa3_stop_gsi_channel(u32 clnt_hdl)
return res;
}
-void ipa3_suspend_apps_pipes(bool suspend)
+static int _ipa_suspend_pipe(enum ipa_client_type client, bool suspend)
{
- struct ipa_ep_cfg_ctrl cfg;
int ipa_ep_idx;
struct ipa3_ep_context *ep;
int res;
- memset(&cfg, 0, sizeof(cfg));
- cfg.ipa_ep_suspend = suspend;
+ if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) {
+ IPAERR("not supported\n");
+ return -EPERM;
+ }
- ipa_ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_APPS_LAN_CONS);
+ ipa_ep_idx = ipa3_get_ep_mapping(client);
if (ipa_ep_idx < 0) {
- IPAERR("IPA client mapping failed\n");
- ipa_assert();
- return;
+ IPADBG("client %d not configued\n", client);
+ return 0;
}
- ep = &ipa3_ctx->ep[ipa_ep_idx];
- if (ep->valid) {
- IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend",
- ipa_ep_idx);
- /*
- * move the channel to callback mode.
- * This needs to happen before starting the channel to make
- * sure we don't loose any interrupt
- */
- if (!suspend && !atomic_read(&ep->sys->curr_polling_state))
- gsi_config_channel_mode(ep->gsi_chan_hdl,
- GSI_CHAN_MODE_CALLBACK);
- if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
- if (suspend) {
- res = __ipa3_stop_gsi_channel(ipa_ep_idx);
- if (res) {
- IPAERR("failed to stop LAN channel\n");
- ipa_assert();
- }
- } else {
- res = gsi_start_channel(ep->gsi_chan_hdl);
- if (res) {
- IPAERR("failed to start LAN channel\n");
- ipa_assert();
- }
- }
- } else {
- ipa3_cfg_ep_ctrl(ipa_ep_idx, &cfg);
+ ep = &ipa3_ctx->ep[ipa_ep_idx];
+ if (!ep->valid)
+ return 0;
+
+ IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend", ipa_ep_idx);
+ /*
+ * move the channel to callback mode.
+ * This needs to happen before starting the channel to make
+ * sure we don't loose any interrupt
+ */
+ if (!suspend && !atomic_read(&ep->sys->curr_polling_state))
+ gsi_config_channel_mode(ep->gsi_chan_hdl,
+ GSI_CHAN_MODE_CALLBACK);
+
+ if (suspend) {
+ res = __ipa3_stop_gsi_channel(ipa_ep_idx);
+ if (res) {
+ IPAERR("failed to stop LAN channel\n");
+ ipa_assert();
}
- if (suspend)
- ipa3_gsi_poll_after_suspend(ep);
- }
-
- ipa_ep_idx = ipa_get_ep_mapping(IPA_CLIENT_APPS_WAN_CONS);
- /* Considering the case for SSR. */
- if (ipa_ep_idx == -1) {
- IPADBG("Invalid mapping for IPA_CLIENT_APPS_WAN_CONS\n");
- return;
- }
- ep = &ipa3_ctx->ep[ipa_ep_idx];
- if (ep->valid) {
- IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend",
- ipa_ep_idx);
- /*
- * move the channel to callback mode.
- * This needs to happen before starting the channel to make
- * sure we don't loose any interrupt
- */
- if (!suspend && !atomic_read(&ep->sys->curr_polling_state))
- gsi_config_channel_mode(ep->gsi_chan_hdl,
- GSI_CHAN_MODE_CALLBACK);
- if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
- if (suspend) {
- res = __ipa3_stop_gsi_channel(ipa_ep_idx);
- if (res) {
- IPAERR("failed to stop WAN channel\n");
- ipa_assert();
- }
- } else if (!atomic_read(&ipa3_ctx->is_ssr)) {
- /* If SSR was alreday started not required to
- * start WAN channel,Because in SSR will stop
- * channel and reset the channel.
- */
- res = gsi_start_channel(ep->gsi_chan_hdl);
- if (res) {
- IPAERR("failed to start WAN channel\n");
- ipa_assert();
- }
- }
- } else {
- ipa3_cfg_ep_ctrl(ipa_ep_idx, &cfg);
+ } else {
+ res = gsi_start_channel(ep->gsi_chan_hdl);
+ if (res) {
+ IPAERR("failed to start LAN channel\n");
+ ipa_assert();
}
- if (suspend)
- ipa3_gsi_poll_after_suspend(ep);
}
- ipa_ep_idx = ipa_get_ep_mapping(IPA_CLIENT_ODL_DPL_CONS);
- /* Considering the case for SSR. */
- if (ipa_ep_idx == -1) {
- IPADBG("Invalid mapping for IPA_CLIENT_ODL_DPL_CONS\n");
- return;
- }
- ep = &ipa3_ctx->ep[ipa_ep_idx];
- if (ep->valid) {
- IPADBG("%s pipe %d\n", suspend ? "suspend" : "unsuspend",
- ipa_ep_idx);
- /*
- * move the channel to callback mode.
- * This needs to happen before starting the channel to make
- * sure we don't loose any interrupt
- */
- if (!suspend && !atomic_read(&ep->sys->curr_polling_state))
- gsi_config_channel_mode(ep->gsi_chan_hdl,
+ if (suspend) {
+ IPADBG("switch ch %ld to poll\n", ep->gsi_chan_hdl);
+ gsi_config_channel_mode(ep->gsi_chan_hdl, GSI_CHAN_MODE_POLL);
+ if (!ipa3_gsi_channel_is_quite(ep))
+ return -EAGAIN;
+ } else if (!atomic_read(&ep->sys->curr_polling_state)) {
+ IPADBG("switch ch %ld to callback\n", ep->gsi_chan_hdl);
+ gsi_config_channel_mode(ep->gsi_chan_hdl,
GSI_CHAN_MODE_CALLBACK);
- if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) {
- if (suspend) {
- res = __ipa3_stop_gsi_channel(ipa_ep_idx);
- if (res) {
- IPAERR("failed to stop ODL channel\n");
- ipa_assert();
- }
- } else if (!atomic_read(&ipa3_ctx->is_ssr)) {
- /* If SSR was alreday started not required to
- * start WAN channel,Because in SSR will stop
- * channel and reset the channel.
- */
- res = gsi_start_channel(ep->gsi_chan_hdl);
- if (res) {
- IPAERR("failed to start ODL channel\n");
- ipa_assert();
- }
- }
- } else {
- ipa3_cfg_ep_ctrl(ipa_ep_idx, &cfg);
- }
- if (suspend)
- ipa3_gsi_poll_after_suspend(ep);
}
+
+ return 0;
+}
+
+int ipa3_suspend_apps_pipes(bool suspend)
+{
+ int res;
+
+ res = _ipa_suspend_pipe(IPA_CLIENT_APPS_LAN_CONS, suspend);
+ if (res)
+ return res;
+
+ res = _ipa_suspend_pipe(IPA_CLIENT_APPS_WAN_CONS, suspend);
+ if (res)
+ return res;
+
+ return 0;
}
int ipa3_allocate_dma_task_for_gsi(void)
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index 37246e1..3390354 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
@@ -1228,7 +1228,7 @@ static int ipa3_wwan_xmit(struct sk_buff *skb, struct net_device *dev)
struct ipa3_wwan_private *wwan_ptr = netdev_priv(dev);
unsigned long flags;
- if (rmnet_ipa3_ctx->ipa_config_is_apq) {
+ if (unlikely(rmnet_ipa3_ctx->ipa_config_is_apq)) {
IPAWANERR_RL("IPA embedded data on APQ platform\n");
dev_kfree_skb_any(skb);
dev->stats.tx_dropped++;
@@ -1295,7 +1295,8 @@ static int ipa3_wwan_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&wwan_ptr->lock, flags);
return NETDEV_TX_BUSY;
}
- if (ret) {
+
+ if (unlikely(ret)) {
IPAWANERR("[%s] fatal: ipa pm activate failed %d\n",
dev->name, ret);
dev_kfree_skb_any(skb);
@@ -1318,7 +1319,7 @@ static int ipa3_wwan_xmit(struct sk_buff *skb, struct net_device *dev)
* IPA_CLIENT_Q6_WAN_CONS based on status configuration
*/
ret = ipa3_tx_dp(IPA_CLIENT_APPS_WAN_PROD, skb, NULL);
- if (ret) {
+ if (unlikely(ret)) {
atomic_dec(&wwan_ptr->outstanding_pkts);
if (ret == -EPIPE) {
IPAWANERR_RL("[%s] fatal: pipe is not valid\n",
@@ -1419,7 +1420,7 @@ static void apps_ipa_packet_receive_notify(void *priv,
{
struct net_device *dev = (struct net_device *)priv;
- if (evt == IPA_RECEIVE) {
+ if (likely(evt == IPA_RECEIVE)) {
struct sk_buff *skb = (struct sk_buff *)data;
int result;
unsigned int packet_len = skb->len;
@@ -1442,7 +1443,7 @@ static void apps_ipa_packet_receive_notify(void *priv,
}
}
- if (result) {
+ if (unlikely(result)) {
pr_err_ratelimited(DEV_NAME " %s:%d fail on netif_receive_skb\n",
__func__, __LINE__);
dev->stats.rx_dropped++;
diff --git a/drivers/platform/msm/qcom-geni-se.c b/drivers/platform/msm/qcom-geni-se.c
index acfecd1..2750425 100644
--- a/drivers/platform/msm/qcom-geni-se.c
+++ b/drivers/platform/msm/qcom-geni-se.c
@@ -3,7 +3,6 @@
* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
*/
-#include <asm/dma-iommu.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/ipc_logging.h>
@@ -1365,56 +1364,6 @@ EXPORT_SYMBOL(geni_se_qupv3_hw_version);
static int geni_se_iommu_map_and_attach(struct geni_se_device *geni_se_dev)
{
- dma_addr_t va_start = GENI_SE_IOMMU_VA_START;
- size_t va_size = GENI_SE_IOMMU_VA_SIZE;
- int bypass = 1;
- struct device *cb_dev = geni_se_dev->cb_dev;
-
- /*Don't proceed if IOMMU node is disabled*/
- if (!iommu_present(&platform_bus_type))
- return 0;
-
- mutex_lock(&geni_se_dev->iommu_lock);
- if (likely(geni_se_dev->iommu_map)) {
- mutex_unlock(&geni_se_dev->iommu_lock);
- return 0;
- }
-
- geni_se_dev->iommu_map =
- __depr_arm_iommu_create_mapping(&platform_bus_type,
- va_start, va_size);
- if (IS_ERR(geni_se_dev->iommu_map)) {
- GENI_SE_ERR(geni_se_dev->log_ctx, false, NULL,
- "%s:%s iommu_create_mapping failure\n",
- __func__, dev_name(cb_dev));
- mutex_unlock(&geni_se_dev->iommu_lock);
- return PTR_ERR(geni_se_dev->iommu_map);
- }
-
- if (geni_se_dev->iommu_s1_bypass &&
- iommu_domain_set_attr(geni_se_dev->iommu_map->domain,
- DOMAIN_ATTR_S1_BYPASS, &bypass)) {
- GENI_SE_ERR(geni_se_dev->log_ctx, false, NULL,
- "%s:%s Couldn't bypass s1 translation\n",
- __func__, dev_name(cb_dev));
- __depr_arm_iommu_release_mapping(geni_se_dev->iommu_map);
- geni_se_dev->iommu_map = NULL;
- mutex_unlock(&geni_se_dev->iommu_lock);
- return -EIO;
- }
-
- if (__depr_arm_iommu_attach_device(cb_dev, geni_se_dev->iommu_map)) {
- GENI_SE_ERR(geni_se_dev->log_ctx, false, NULL,
- "%s:%s couldn't arm_iommu_attach_device\n",
- __func__, dev_name(cb_dev));
- __depr_arm_iommu_release_mapping(geni_se_dev->iommu_map);
- geni_se_dev->iommu_map = NULL;
- mutex_unlock(&geni_se_dev->iommu_lock);
- return -EIO;
- }
- mutex_unlock(&geni_se_dev->iommu_lock);
- GENI_SE_DBG(geni_se_dev->log_ctx, false, NULL, "%s:%s successful\n",
- __func__, dev_name(cb_dev));
return 0;
}
@@ -1856,10 +1805,6 @@ static int geni_se_remove(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct geni_se_device *geni_se_dev = dev_get_drvdata(dev);
- if (likely(!IS_ERR_OR_NULL(geni_se_dev->iommu_map))) {
- __depr_arm_iommu_detach_device(geni_se_dev->cb_dev);
- __depr_arm_iommu_release_mapping(geni_se_dev->iommu_map);
- }
ipc_log_context_destroy(geni_se_dev->log_ctx);
devm_iounmap(dev, geni_se_dev->base);
devm_kfree(dev, geni_se_dev);
diff --git a/drivers/power/supply/qcom/qg-battery-profile.c b/drivers/power/supply/qcom/qg-battery-profile.c
index cc46ea5..928fb6e 100644
--- a/drivers/power/supply/qcom/qg-battery-profile.c
+++ b/drivers/power/supply/qcom/qg-battery-profile.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
*/
#define pr_fmt(fmt) "QG-K: %s: " fmt, __func__
@@ -100,7 +100,8 @@ static long qg_battery_data_ioctl(struct file *file, unsigned int cmd,
rc = -EINVAL;
} else {
/* OCV is passed as deci-uV - 10^-4 V */
- soc = interpolate_soc(&battery->profile[bp.table_index],
+ soc = qg_interpolate_soc(
+ &battery->profile[bp.table_index],
bp.batt_temp, UV_TO_DECIUV(bp.ocv_uv));
soc = CAP(QG_MIN_SOC, QG_MAX_SOC, soc);
rc = put_user(soc, &bp_user->soc);
@@ -120,7 +121,7 @@ static long qg_battery_data_ioctl(struct file *file, unsigned int cmd,
bp.table_index);
rc = -EINVAL;
} else {
- ocv_uv = interpolate_var(
+ ocv_uv = qg_interpolate_var(
&battery->profile[bp.table_index],
bp.batt_temp, bp.soc);
ocv_uv = DECIUV_TO_UV(ocv_uv);
@@ -142,7 +143,7 @@ static long qg_battery_data_ioctl(struct file *file, unsigned int cmd,
bp.table_index);
rc = -EINVAL;
} else {
- fcc_mah = interpolate_single_row_lut(
+ fcc_mah = qg_interpolate_single_row_lut(
&battery->profile[bp.table_index],
bp.batt_temp, DEGC_SCALE);
fcc_mah = CAP(QG_MIN_FCC_MAH, QG_MAX_FCC_MAH, fcc_mah);
@@ -162,7 +163,8 @@ static long qg_battery_data_ioctl(struct file *file, unsigned int cmd,
bp.table_index);
rc = -EINVAL;
} else {
- var = interpolate_var(&battery->profile[bp.table_index],
+ var = qg_interpolate_var(
+ &battery->profile[bp.table_index],
bp.batt_temp, bp.soc);
var = CAP(QG_MIN_VAR, QG_MAX_VAR, var);
rc = put_user(var, &bp_user->var);
@@ -182,7 +184,7 @@ static long qg_battery_data_ioctl(struct file *file, unsigned int cmd,
bp.table_index);
rc = -EINVAL;
} else {
- slope = interpolate_slope(
+ slope = qg_interpolate_slope(
&battery->profile[bp.table_index],
bp.batt_temp, bp.soc);
slope = CAP(QG_MIN_SLOPE, QG_MAX_SLOPE, slope);
@@ -394,7 +396,7 @@ int lookup_soc_ocv(u32 *soc, u32 ocv_uv, int batt_temp, bool charging)
if (!the_battery || !the_battery->profile_node)
return -ENODEV;
- *soc = interpolate_soc(&the_battery->profile[table_index],
+ *soc = qg_interpolate_soc(&the_battery->profile[table_index],
batt_temp, UV_TO_DECIUV(ocv_uv));
*soc = CAP(0, 100, DIV_ROUND_CLOSEST(*soc, 100));
@@ -410,7 +412,7 @@ int qg_get_nominal_capacity(u32 *nom_cap_uah, int batt_temp, bool charging)
if (!the_battery || !the_battery->profile_node)
return -ENODEV;
- fcc_mah = interpolate_single_row_lut(
+ fcc_mah = qg_interpolate_single_row_lut(
&the_battery->profile[table_index],
batt_temp, DEGC_SCALE);
fcc_mah = CAP(QG_MIN_FCC_MAH, QG_MAX_FCC_MAH, fcc_mah);
diff --git a/drivers/power/supply/qcom/qg-core.h b/drivers/power/supply/qcom/qg-core.h
index 7e0b20c..a0c07de 100644
--- a/drivers/power/supply/qcom/qg-core.h
+++ b/drivers/power/supply/qcom/qg-core.h
@@ -57,6 +57,7 @@ struct qg_dt {
int shutdown_soc_threshold;
int min_sleep_time_secs;
int sys_min_volt_mv;
+ int fvss_vbat_mv;
bool hold_soc_while_full;
bool linearize_soc;
bool cl_disable;
@@ -67,6 +68,7 @@ struct qg_dt {
bool use_s7_ocv;
bool qg_sleep_config;
bool qg_fast_chg_cfg;
+ bool fvss_enable;
};
struct qg_esr_data {
@@ -129,6 +131,7 @@ struct qpnp_qg {
bool dc_present;
bool charge_full;
bool force_soc;
+ bool fvss_active;
int charge_status;
int charge_type;
int chg_iterm_ma;
@@ -137,6 +140,8 @@ struct qpnp_qg {
int esr_nominal;
int soh;
int soc_reporting_ready;
+ int last_fifo_v_uv;
+ int last_fifo_i_ua;
u32 fifo_done_count;
u32 wa_flags;
u32 seq_no;
@@ -145,6 +150,8 @@ struct qpnp_qg {
u32 esr_last;
u32 s2_state;
u32 s2_state_mask;
+ u32 soc_fvss_entry;
+ u32 vbat_fvss_entry;
ktime_t last_user_update_time;
ktime_t last_fifo_update_time;
unsigned long last_maint_soc_update_time;
diff --git a/drivers/power/supply/qcom/qg-profile-lib.c b/drivers/power/supply/qcom/qg-profile-lib.c
index 7585dad..bf8efc9 100644
--- a/drivers/power/supply/qcom/qg-profile-lib.c
+++ b/drivers/power/supply/qcom/qg-profile-lib.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
@@ -9,7 +9,7 @@
#include "qg-profile-lib.h"
#include "qg-defs.h"
-static int linear_interpolate(int y0, int x0, int y1, int x1, int x)
+int qg_linear_interpolate(int y0, int x0, int y1, int x1, int x)
{
if (y0 == y1 || x == x0)
return y0;
@@ -19,7 +19,7 @@ static int linear_interpolate(int y0, int x0, int y1, int x1, int x)
return y0 + ((y1 - y0) * (x - x0) / (x1 - x0));
}
-int interpolate_single_row_lut(struct profile_table_data *lut,
+int qg_interpolate_single_row_lut(struct profile_table_data *lut,
int x, int scale)
{
int i, result;
@@ -45,7 +45,7 @@ int interpolate_single_row_lut(struct profile_table_data *lut,
if (x == lut->col_entries[i] * scale) {
result = lut->data[0][i];
} else {
- result = linear_interpolate(
+ result = qg_linear_interpolate(
lut->data[0][i-1],
lut->col_entries[i-1] * scale,
lut->data[0][i],
@@ -56,7 +56,7 @@ int interpolate_single_row_lut(struct profile_table_data *lut,
return result;
}
-int interpolate_soc(struct profile_table_data *lut,
+int qg_interpolate_soc(struct profile_table_data *lut,
int batt_temp, int ocv)
{
int i, j, soc_high, soc_low, soc;
@@ -87,7 +87,7 @@ int interpolate_soc(struct profile_table_data *lut,
if (ocv >= lut->data[i][j]) {
if (ocv == lut->data[i][j])
return lut->row_entries[i];
- soc = linear_interpolate(
+ soc = qg_linear_interpolate(
lut->row_entries[i],
lut->data[i][j],
lut->row_entries[i - 1],
@@ -108,7 +108,7 @@ int interpolate_soc(struct profile_table_data *lut,
for (i = 0; i < rows-1; i++) {
if (soc_high == 0 && is_between(lut->data[i][j],
lut->data[i+1][j], ocv)) {
- soc_high = linear_interpolate(
+ soc_high = qg_linear_interpolate(
lut->row_entries[i],
lut->data[i][j],
lut->row_entries[i + 1],
@@ -118,7 +118,7 @@ int interpolate_soc(struct profile_table_data *lut,
if (soc_low == 0 && is_between(lut->data[i][j-1],
lut->data[i+1][j-1], ocv)) {
- soc_low = linear_interpolate(
+ soc_low = qg_linear_interpolate(
lut->row_entries[i],
lut->data[i][j-1],
lut->row_entries[i + 1],
@@ -127,7 +127,7 @@ int interpolate_soc(struct profile_table_data *lut,
}
if (soc_high && soc_low) {
- soc = linear_interpolate(
+ soc = qg_linear_interpolate(
soc_low,
lut->col_entries[j-1] * DEGC_SCALE,
soc_high,
@@ -148,7 +148,7 @@ int interpolate_soc(struct profile_table_data *lut,
return 10000;
}
-int interpolate_var(struct profile_table_data *lut,
+int qg_interpolate_var(struct profile_table_data *lut,
int batt_temp, int soc)
{
int i, var1, var2, var, rows, cols;
@@ -192,7 +192,7 @@ int interpolate_var(struct profile_table_data *lut,
break;
if (batt_temp == lut->col_entries[i] * DEGC_SCALE) {
- var = linear_interpolate(
+ var = qg_linear_interpolate(
lut->data[row1][i],
lut->row_entries[row1],
lut->data[row2][i],
@@ -201,21 +201,21 @@ int interpolate_var(struct profile_table_data *lut,
return var;
}
- var1 = linear_interpolate(
+ var1 = qg_linear_interpolate(
lut->data[row1][i - 1],
lut->col_entries[i - 1] * DEGC_SCALE,
lut->data[row1][i],
lut->col_entries[i] * DEGC_SCALE,
batt_temp);
- var2 = linear_interpolate(
+ var2 = qg_linear_interpolate(
lut->data[row2][i - 1],
lut->col_entries[i - 1] * DEGC_SCALE,
lut->data[row2][i],
lut->col_entries[i] * DEGC_SCALE,
batt_temp);
- var = linear_interpolate(
+ var = qg_linear_interpolate(
var1,
lut->row_entries[row1],
var2,
@@ -225,7 +225,7 @@ int interpolate_var(struct profile_table_data *lut,
return var;
}
-int interpolate_slope(struct profile_table_data *lut,
+int qg_interpolate_slope(struct profile_table_data *lut,
int batt_temp, int soc)
{
int i, ocvrow1, ocvrow2, rows, cols;
@@ -277,14 +277,14 @@ int interpolate_slope(struct profile_table_data *lut,
lut->row_entries[row2]);
return slope;
}
- ocvrow1 = linear_interpolate(
+ ocvrow1 = qg_linear_interpolate(
lut->data[row1][i - 1],
lut->col_entries[i - 1] * DEGC_SCALE,
lut->data[row1][i],
lut->col_entries[i] * DEGC_SCALE,
batt_temp);
- ocvrow2 = linear_interpolate(
+ ocvrow2 = qg_linear_interpolate(
lut->data[row2][i - 1],
lut->col_entries[i - 1] * DEGC_SCALE,
lut->data[row2][i],
diff --git a/drivers/power/supply/qcom/qg-profile-lib.h b/drivers/power/supply/qcom/qg-profile-lib.h
index 5585239..ba7e03e 100644
--- a/drivers/power/supply/qcom/qg-profile-lib.h
+++ b/drivers/power/supply/qcom/qg-profile-lib.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
*/
#ifndef __QG_PROFILE_LIB_H__
@@ -15,13 +15,14 @@ struct profile_table_data {
int **data;
};
-int interpolate_single_row_lut(struct profile_table_data *lut,
+int qg_linear_interpolate(int y0, int x0, int y1, int x1, int x);
+int qg_interpolate_single_row_lut(struct profile_table_data *lut,
int x, int scale);
-int interpolate_soc(struct profile_table_data *lut,
+int qg_interpolate_soc(struct profile_table_data *lut,
int batt_temp, int ocv);
-int interpolate_var(struct profile_table_data *lut,
+int qg_interpolate_var(struct profile_table_data *lut,
int batt_temp, int soc);
-int interpolate_slope(struct profile_table_data *lut,
+int qg_interpolate_slope(struct profile_table_data *lut,
int batt_temp, int soc);
#endif /*__QG_PROFILE_LIB_H__ */
diff --git a/drivers/power/supply/qcom/qg-soc.c b/drivers/power/supply/qcom/qg-soc.c
index d8d0c6e..690ac02 100644
--- a/drivers/power/supply/qcom/qg-soc.c
+++ b/drivers/power/supply/qcom/qg-soc.c
@@ -17,6 +17,7 @@
#include "qg-reg.h"
#include "qg-util.h"
#include "qg-defs.h"
+#include "qg-profile-lib.h"
#include "qg-soc.h"
#define DEFAULT_UPDATE_TIME_MS 64000
@@ -45,6 +46,11 @@ static ssize_t soc_interval_ms_store(struct device *dev,
}
DEVICE_ATTR_RW(soc_interval_ms);
+static int qg_fvss_delta_soc_interval_ms = 10000;
+module_param_named(
+ fvss_soc_interval_ms, qg_fvss_delta_soc_interval_ms, int, 0600
+);
+
static int qg_delta_soc_cold_interval_ms = 4000;
static ssize_t soc_cold_interval_ms_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -87,6 +93,84 @@ static ssize_t maint_soc_update_ms_store(struct device *dev,
}
DEVICE_ATTR_RW(maint_soc_update_ms);
+/* FVSS scaling only based on VBAT */
+static int qg_fvss_vbat_scaling = 1;
+module_param_named(
+ fvss_vbat_scaling, qg_fvss_vbat_scaling, int, 0600
+);
+
+static int qg_process_fvss_soc(struct qpnp_qg *chip, int sys_soc)
+{
+ int rc, vbat_uv = 0, vbat_cutoff_uv = chip->dt.vbatt_cutoff_mv * 1000;
+ int soc_vbat = 0, wt_vbat = 0, wt_sys = 0, soc_fvss = 0;
+
+ if (!chip->dt.fvss_enable)
+ return 0;
+
+ if (chip->charge_status == POWER_SUPPLY_STATUS_CHARGING)
+ goto exit_soc_scale;
+
+ rc = qg_get_battery_voltage(chip, &vbat_uv);
+ if (rc < 0)
+ goto exit_soc_scale;
+
+ if (!chip->last_fifo_v_uv)
+ chip->last_fifo_v_uv = vbat_uv;
+
+ if (chip->last_fifo_v_uv > (chip->dt.fvss_vbat_mv * 1000)) {
+ qg_dbg(chip, QG_DEBUG_SOC, "FVSS: last_fifo_v=%d fvss_entry_uv=%d - exit\n",
+ chip->last_fifo_v_uv, chip->dt.fvss_vbat_mv * 1000);
+ goto exit_soc_scale;
+ }
+
+ /* Enter FVSS */
+ if (!chip->fvss_active) {
+ chip->vbat_fvss_entry = CAP(vbat_cutoff_uv,
+ chip->dt.fvss_vbat_mv * 1000,
+ chip->last_fifo_v_uv);
+ chip->soc_fvss_entry = sys_soc;
+ chip->fvss_active = true;
+ } else if (chip->last_fifo_v_uv > chip->vbat_fvss_entry) {
+ /* VBAT has gone beyond the entry voltage */
+ chip->vbat_fvss_entry = chip->last_fifo_v_uv;
+ chip->soc_fvss_entry = sys_soc;
+ }
+
+ soc_vbat = qg_linear_interpolate(chip->soc_fvss_entry,
+ chip->vbat_fvss_entry,
+ 0,
+ vbat_cutoff_uv,
+ chip->last_fifo_v_uv);
+ soc_vbat = CAP(0, 100, soc_vbat);
+
+ if (qg_fvss_vbat_scaling) {
+ wt_vbat = 100;
+ wt_sys = 0;
+ } else {
+ wt_sys = qg_linear_interpolate(100,
+ chip->soc_fvss_entry,
+ 0,
+ 0,
+ sys_soc);
+ wt_sys = CAP(0, 100, wt_sys);
+ wt_vbat = 100 - wt_sys;
+ }
+
+ soc_fvss = ((soc_vbat * wt_vbat) + (sys_soc * wt_sys)) / 100;
+ soc_fvss = CAP(0, 100, soc_fvss);
+
+ qg_dbg(chip, QG_DEBUG_SOC, "FVSS: vbat_fvss_entry=%d soc_fvss_entry=%d cutoff_uv=%d vbat_uv=%d fifo_avg_v=%d soc_vbat=%d sys_soc=%d wt_vbat=%d wt_sys=%d soc_fvss=%d\n",
+ chip->vbat_fvss_entry, chip->soc_fvss_entry,
+ vbat_cutoff_uv, vbat_uv, chip->last_fifo_v_uv,
+ soc_vbat, sys_soc, wt_vbat, wt_sys, soc_fvss);
+
+ return soc_fvss;
+
+exit_soc_scale:
+ chip->fvss_active = false;
+ return sys_soc;
+}
+
int qg_adjust_sys_soc(struct qpnp_qg *chip)
{
int soc, vbat_uv, rc;
@@ -113,8 +197,11 @@ int qg_adjust_sys_soc(struct qpnp_qg *chip)
soc = DIV_ROUND_CLOSEST(chip->sys_soc, 100);
}
- qg_dbg(chip, QG_DEBUG_SOC, "last_adj_sys_soc=%d adj_sys_soc=%d\n",
- chip->last_adj_ssoc, soc);
+ qg_dbg(chip, QG_DEBUG_SOC, "sys_soc=%d adjusted sys_soc=%d\n",
+ chip->sys_soc, soc);
+
+ soc = qg_process_fvss_soc(chip, soc);
+
chip->last_adj_ssoc = soc;
return soc;
@@ -144,6 +231,8 @@ static void get_next_update_time(struct qpnp_qg *chip)
else if (chip->maint_soc > 0 && chip->maint_soc >= chip->recharge_soc)
/* if in maintenance mode scale slower */
min_delta_soc_interval_ms = qg_maint_soc_update_ms;
+ else if (chip->fvss_active)
+ min_delta_soc_interval_ms = qg_fvss_delta_soc_interval_ms;
if (!min_delta_soc_interval_ms)
min_delta_soc_interval_ms = 1000; /* 1 second */
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen4.c b/drivers/power/supply/qcom/qpnp-fg-gen4.c
index 24e8319..a868f1d 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen4.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen4.c
@@ -2493,8 +2493,8 @@ static void profile_load_work(struct work_struct *work)
out:
if (!chip->esr_fast_calib || is_debug_batt_id(fg)) {
/* If it is debug battery, then disable ESR fast calibration */
- chip->esr_fast_calib = false;
fg_gen4_esr_fast_calib_config(chip, false);
+ chip->esr_fast_calib = false;
}
if (chip->dt.multi_profile_load && rc < 0)
diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c
index 6c85dd9..3c8ec13 100644
--- a/drivers/power/supply/qcom/qpnp-qg.c
+++ b/drivers/power/supply/qcom/qpnp-qg.c
@@ -493,6 +493,9 @@ static int qg_process_fifo(struct qpnp_qg *chip, u32 fifo_length)
chip->kdata.fifo[j].interval = sample_interval;
chip->kdata.fifo[j].count = sample_count;
+ chip->last_fifo_v_uv = chip->kdata.fifo[j].v;
+ chip->last_fifo_i_ua = chip->kdata.fifo[j].i;
+
qg_dbg(chip, QG_DEBUG_FIFO, "FIFO %d raw_v=%d uV=%d raw_i=%d uA=%d interval=%d count=%d\n",
j, fifo_v,
chip->kdata.fifo[j].v,
@@ -557,6 +560,9 @@ static int qg_process_accumulator(struct qpnp_qg *chip)
if (chip->kdata.fifo_length == MAX_FIFO_LENGTH)
chip->kdata.fifo_length = MAX_FIFO_LENGTH - 1;
+ chip->last_fifo_v_uv = chip->kdata.fifo[index].v;
+ chip->last_fifo_i_ua = chip->kdata.fifo[index].i;
+
if (chip->kdata.fifo_length == 1) /* Only accumulator data */
chip->kdata.seq_no = chip->seq_no++ % U32_MAX;
@@ -2101,6 +2107,9 @@ static int qg_psy_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_POWER_AVG:
rc = qg_get_power(chip, &pval->intval, true);
break;
+ case POWER_SUPPLY_PROP_SCALE_MODE_EN:
+ pval->intval = chip->fvss_active;
+ break;
default:
pr_debug("Unsupported property %d\n", psp);
break;
@@ -2159,6 +2168,7 @@ static enum power_supply_property qg_psy_props[] = {
POWER_SUPPLY_PROP_VOLTAGE_AVG,
POWER_SUPPLY_PROP_POWER_AVG,
POWER_SUPPLY_PROP_POWER_NOW,
+ POWER_SUPPLY_PROP_SCALE_MODE_EN,
};
static const struct power_supply_desc qg_psy_desc = {
@@ -2578,6 +2588,12 @@ static ssize_t qg_device_read(struct file *file, char __user *buf, size_t count,
struct qpnp_qg *chip = file->private_data;
unsigned long data_size = sizeof(chip->kdata);
+ if (count < data_size) {
+ pr_err("Invalid datasize %lu, expected lesser then %zu\n",
+ data_size, count);
+ return -EINVAL;
+ }
+
/* non-blocking access, return */
if (!chip->data_ready && (file->f_flags & O_NONBLOCK))
return 0;
@@ -3812,6 +3828,7 @@ static int qg_parse_cl_dt(struct qpnp_qg *chip)
#define ESR_CHG_MIN_IBAT_UA (-450000)
#define DEFAULT_SLEEP_TIME_SECS 1800 /* 30 mins */
#define DEFAULT_SYS_MIN_VOLT_MV 2800
+#define DEFAULT_FVSS_VBAT_MV 3500
static int qg_parse_dt(struct qpnp_qg *chip)
{
int rc = 0;
@@ -4043,6 +4060,18 @@ static int qg_parse_dt(struct qpnp_qg *chip)
else
chip->dt.min_sleep_time_secs = temp;
+ if (of_property_read_bool(node, "qcom,fvss-enable")) {
+
+ chip->dt.fvss_enable = true;
+
+ rc = of_property_read_u32(node,
+ "qcom,fvss-vbatt-mv", &temp);
+ if (rc < 0)
+ chip->dt.fvss_vbat_mv = DEFAULT_FVSS_VBAT_MV;
+ else
+ chip->dt.fvss_vbat_mv = temp;
+ }
+
qg_dbg(chip, QG_DEBUG_PON, "DT: vbatt_empty_mv=%dmV vbatt_low_mv=%dmV delta_soc=%d ext-sns=%d\n",
chip->dt.vbatt_empty_mv, chip->dt.vbatt_low_mv,
chip->dt.delta_soc, chip->dt.qg_ext_sense);
diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c
index a3f192b..9a00920 100644
--- a/drivers/power/supply/qcom/qpnp-smb5.c
+++ b/drivers/power/supply/qcom/qpnp-smb5.c
@@ -2115,6 +2115,10 @@ static int smb5_configure_micro_usb(struct smb_charger *chg)
}
}
+ /* Enable HVDCP detection and authentication */
+ if (!chg->hvdcp_disable)
+ smblib_hvdcp_detect_enable(chg, true);
+
return rc;
}
diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c
index 8febacb..0951564 100644
--- a/drivers/pps/pps.c
+++ b/drivers/pps/pps.c
@@ -166,6 +166,14 @@ static long pps_cdev_ioctl(struct file *file,
pps->params.mode |= PPS_CANWAIT;
pps->params.api_version = PPS_API_VERS;
+ /*
+ * Clear unused fields of pps_kparams to avoid leaking
+ * uninitialized data of the PPS_SETPARAMS caller via
+ * PPS_GETPARAMS
+ */
+ pps->params.assert_off_tu.flags = 0;
+ pps->params.clear_off_tu.flags = 0;
+
spin_unlock_irq(&pps->lock);
break;
diff --git a/drivers/rapidio/devices/rio_mport_cdev.c b/drivers/rapidio/devices/rio_mport_cdev.c
index cbe467f..fa0bbda 100644
--- a/drivers/rapidio/devices/rio_mport_cdev.c
+++ b/drivers/rapidio/devices/rio_mport_cdev.c
@@ -1688,6 +1688,7 @@ static int rio_mport_add_riodev(struct mport_cdev_priv *priv,
if (copy_from_user(&dev_info, arg, sizeof(dev_info)))
return -EFAULT;
+ dev_info.name[sizeof(dev_info.name) - 1] = '\0';
rmcd_debug(RDEV, "name:%s ct:0x%x did:0x%x hc:0x%x", dev_info.name,
dev_info.comptag, dev_info.destid, dev_info.hopcount);
@@ -1819,6 +1820,7 @@ static int rio_mport_del_riodev(struct mport_cdev_priv *priv, void __user *arg)
if (copy_from_user(&dev_info, arg, sizeof(dev_info)))
return -EFAULT;
+ dev_info.name[sizeof(dev_info.name) - 1] = '\0';
mport = priv->md->mport;
diff --git a/drivers/ras/cec.c b/drivers/ras/cec.c
index f85d6b7..5d2b2c02 100644
--- a/drivers/ras/cec.c
+++ b/drivers/ras/cec.c
@@ -369,7 +369,9 @@ static int pfn_set(void *data, u64 val)
{
*(u64 *)data = val;
- return cec_add_elem(val);
+ cec_add_elem(val);
+
+ return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(pfn_ops, u64_get, pfn_set, "0x%llx\n");
diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c
index c584bd1..7c598c1 100644
--- a/drivers/regulator/s2mps11.c
+++ b/drivers/regulator/s2mps11.c
@@ -373,8 +373,8 @@ static const struct regulator_desc s2mps11_regulators[] = {
regulator_desc_s2mps11_buck1_4(4),
regulator_desc_s2mps11_buck5,
regulator_desc_s2mps11_buck67810(6, MIN_600_MV, STEP_6_25_MV),
- regulator_desc_s2mps11_buck67810(7, MIN_600_MV, STEP_12_5_MV),
- regulator_desc_s2mps11_buck67810(8, MIN_600_MV, STEP_12_5_MV),
+ regulator_desc_s2mps11_buck67810(7, MIN_750_MV, STEP_12_5_MV),
+ regulator_desc_s2mps11_buck67810(8, MIN_750_MV, STEP_12_5_MV),
regulator_desc_s2mps11_buck9,
regulator_desc_s2mps11_buck67810(10, MIN_750_MV, STEP_12_5_MV),
};
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c
index b9ce93e..99f8661 100644
--- a/drivers/s390/block/dasd_alias.c
+++ b/drivers/s390/block/dasd_alias.c
@@ -383,6 +383,20 @@ suborder_not_supported(struct dasd_ccw_req *cqr)
char msg_format;
char msg_no;
+ /*
+ * intrc values ENODEV, ENOLINK and EPERM
+ * will be optained from sleep_on to indicate that no
+ * IO operation can be started
+ */
+ if (cqr->intrc == -ENODEV)
+ return 1;
+
+ if (cqr->intrc == -ENOLINK)
+ return 1;
+
+ if (cqr->intrc == -EPERM)
+ return 1;
+
sense = dasd_get_sense(&cqr->irb);
if (!sense)
return 0;
@@ -447,12 +461,8 @@ static int read_unit_address_configuration(struct dasd_device *device,
lcu->flags &= ~NEED_UAC_UPDATE;
spin_unlock_irqrestore(&lcu->lock, flags);
- do {
- rc = dasd_sleep_on(cqr);
- if (rc && suborder_not_supported(cqr))
- return -EOPNOTSUPP;
- } while (rc && (cqr->retries > 0));
- if (rc) {
+ rc = dasd_sleep_on(cqr);
+ if (rc && !suborder_not_supported(cqr)) {
spin_lock_irqsave(&lcu->lock, flags);
lcu->flags |= NEED_UAC_UPDATE;
spin_unlock_irqrestore(&lcu->lock, flags);
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 9c7d9da..4ac4a73 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -749,6 +749,7 @@ static int get_outbound_buffer_frontier(struct qdio_q *q)
switch (state) {
case SLSB_P_OUTPUT_EMPTY:
+ case SLSB_P_OUTPUT_PENDING:
/* the adapter got it */
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr,
"out empty:%1d %02x", q->nr, count);
diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c
index 78f1be4..034528a 100644
--- a/drivers/s390/cio/qdio_setup.c
+++ b/drivers/s390/cio/qdio_setup.c
@@ -151,6 +151,7 @@ static int __qdio_allocate_qs(struct qdio_q **irq_ptr_qs, int nr_queues)
return -ENOMEM;
}
irq_ptr_qs[i] = q;
+ INIT_LIST_HEAD(&q->entry);
}
return 0;
}
@@ -179,6 +180,7 @@ static void setup_queues_misc(struct qdio_q *q, struct qdio_irq *irq_ptr,
q->mask = 1 << (31 - i);
q->nr = i;
q->handler = handler;
+ INIT_LIST_HEAD(&q->entry);
}
static void setup_storage_lists(struct qdio_q *q, struct qdio_irq *irq_ptr,
diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c
index 07dea60..6628e0c 100644
--- a/drivers/s390/cio/qdio_thinint.c
+++ b/drivers/s390/cio/qdio_thinint.c
@@ -79,7 +79,6 @@ void tiqdio_add_input_queues(struct qdio_irq *irq_ptr)
mutex_lock(&tiq_list_lock);
list_add_rcu(&irq_ptr->input_qs[0]->entry, &tiq_list);
mutex_unlock(&tiq_list_lock);
- xchg(irq_ptr->dsci, 1 << 7);
}
void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr)
@@ -87,14 +86,14 @@ void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr)
struct qdio_q *q;
q = irq_ptr->input_qs[0];
- /* if establish triggered an error */
- if (!q || !q->entry.prev || !q->entry.next)
+ if (!q)
return;
mutex_lock(&tiq_list_lock);
list_del_rcu(&q->entry);
mutex_unlock(&tiq_list_lock);
synchronize_rcu();
+ INIT_LIST_HEAD(&q->entry);
}
static inline int has_multiple_inq_on_dsci(struct qdio_irq *irq_ptr)
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index ebdbc45..332701d 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -11,6 +11,7 @@
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/kthread.h>
+#include <linux/bug.h>
#include "zfcp_ext.h"
#include "zfcp_reqlist.h"
@@ -238,6 +239,12 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status,
struct zfcp_erp_action *erp_action;
struct zfcp_scsi_dev *zfcp_sdev;
+ if (WARN_ON_ONCE(need != ZFCP_ERP_ACTION_REOPEN_LUN &&
+ need != ZFCP_ERP_ACTION_REOPEN_PORT &&
+ need != ZFCP_ERP_ACTION_REOPEN_PORT_FORCED &&
+ need != ZFCP_ERP_ACTION_REOPEN_ADAPTER))
+ return NULL;
+
switch (need) {
case ZFCP_ERP_ACTION_REOPEN_LUN:
zfcp_sdev = sdev_to_zfcp(sdev);
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index 90ea0f5..5160d62 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -710,6 +710,8 @@ static void NCR5380_main(struct work_struct *work)
NCR5380_information_transfer(instance);
done = 0;
}
+ if (!hostdata->connected)
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
spin_unlock_irq(&hostdata->lock);
if (!done)
cond_resched();
@@ -984,7 +986,7 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance,
if (!hostdata->selecting) {
/* Command was aborted */
NCR5380_write(MODE_REG, MR_BASE);
- goto out;
+ return NULL;
}
if (err < 0) {
NCR5380_write(MODE_REG, MR_BASE);
@@ -1033,7 +1035,7 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance,
if (!hostdata->selecting) {
NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- goto out;
+ return NULL;
}
dsprintk(NDEBUG_ARBITRATION, instance, "won arbitration\n");
@@ -1106,8 +1108,6 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance,
spin_lock_irq(&hostdata->lock);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
NCR5380_reselect(instance);
- if (!hostdata->connected)
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
shost_printk(KERN_ERR, instance, "reselection after won arbitration?\n");
goto out;
}
@@ -1115,14 +1115,16 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance,
if (err < 0) {
spin_lock_irq(&hostdata->lock);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+
/* Can't touch cmd if it has been reclaimed by the scsi ML */
- if (hostdata->selecting) {
- cmd->result = DID_BAD_TARGET << 16;
- complete_cmd(instance, cmd);
- dsprintk(NDEBUG_SELECTION, instance, "target did not respond within 250ms\n");
- cmd = NULL;
- }
+ if (!hostdata->selecting)
+ return NULL;
+
+ cmd->result = DID_BAD_TARGET << 16;
+ complete_cmd(instance, cmd);
+ dsprintk(NDEBUG_SELECTION, instance,
+ "target did not respond within 250ms\n");
+ cmd = NULL;
goto out;
}
@@ -1150,12 +1152,11 @@ static struct scsi_cmnd *NCR5380_select(struct Scsi_Host *instance,
if (err < 0) {
shost_printk(KERN_ERR, instance, "select: REQ timeout\n");
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
goto out;
}
if (!hostdata->selecting) {
do_abort(instance);
- goto out;
+ return NULL;
}
dsprintk(NDEBUG_SELECTION, instance, "target %d selected, going into MESSAGE OUT phase.\n",
@@ -1817,9 +1818,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
*/
NCR5380_write(TARGET_COMMAND_REG, 0);
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-
maybe_release_dma_irq(instance);
return;
case MESSAGE_REJECT:
@@ -1851,8 +1849,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
*/
NCR5380_write(TARGET_COMMAND_REG, 0);
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
#ifdef SUN3_SCSI_VME
dregs->csr |= CSR_DMA_ENABLE;
#endif
@@ -1954,7 +1950,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
cmd->result = DID_ERROR << 16;
complete_cmd(instance, cmd);
maybe_release_dma_irq(instance);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
return;
}
msgout = NOP;
diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h
index 31096a0..8a6d002 100644
--- a/drivers/scsi/NCR5380.h
+++ b/drivers/scsi/NCR5380.h
@@ -235,7 +235,7 @@ struct NCR5380_cmd {
#define NCR5380_PIO_CHUNK_SIZE 256
/* Time limit (ms) to poll registers when IRQs are disabled, e.g. during PDMA */
-#define NCR5380_REG_POLL_TIME 15
+#define NCR5380_REG_POLL_TIME 10
static inline struct scsi_cmnd *NCR5380_to_scmd(struct NCR5380_cmd *ncmd_ptr)
{
diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c
index 7dc4ffa..24cbd0a 100644
--- a/drivers/scsi/fcoe/fcoe_ctlr.c
+++ b/drivers/scsi/fcoe/fcoe_ctlr.c
@@ -2017,7 +2017,7 @@ EXPORT_SYMBOL_GPL(fcoe_wwn_from_mac);
*/
static inline struct fcoe_rport *fcoe_ctlr_rport(struct fc_rport_priv *rdata)
{
- return (struct fcoe_rport *)(rdata + 1);
+ return container_of(rdata, struct fcoe_rport, rdata);
}
/**
@@ -2281,7 +2281,7 @@ static void fcoe_ctlr_vn_start(struct fcoe_ctlr *fip)
*/
static int fcoe_ctlr_vn_parse(struct fcoe_ctlr *fip,
struct sk_buff *skb,
- struct fc_rport_priv *rdata)
+ struct fcoe_rport *frport)
{
struct fip_header *fiph;
struct fip_desc *desc = NULL;
@@ -2289,16 +2289,12 @@ static int fcoe_ctlr_vn_parse(struct fcoe_ctlr *fip,
struct fip_wwn_desc *wwn = NULL;
struct fip_vn_desc *vn = NULL;
struct fip_size_desc *size = NULL;
- struct fcoe_rport *frport;
size_t rlen;
size_t dlen;
u32 desc_mask = 0;
u32 dtype;
u8 sub;
- memset(rdata, 0, sizeof(*rdata) + sizeof(*frport));
- frport = fcoe_ctlr_rport(rdata);
-
fiph = (struct fip_header *)skb->data;
frport->flags = ntohs(fiph->fip_flags);
@@ -2361,15 +2357,17 @@ static int fcoe_ctlr_vn_parse(struct fcoe_ctlr *fip,
if (dlen != sizeof(struct fip_wwn_desc))
goto len_err;
wwn = (struct fip_wwn_desc *)desc;
- rdata->ids.node_name = get_unaligned_be64(&wwn->fd_wwn);
+ frport->rdata.ids.node_name =
+ get_unaligned_be64(&wwn->fd_wwn);
break;
case FIP_DT_VN_ID:
if (dlen != sizeof(struct fip_vn_desc))
goto len_err;
vn = (struct fip_vn_desc *)desc;
memcpy(frport->vn_mac, vn->fd_mac, ETH_ALEN);
- rdata->ids.port_id = ntoh24(vn->fd_fc_id);
- rdata->ids.port_name = get_unaligned_be64(&vn->fd_wwpn);
+ frport->rdata.ids.port_id = ntoh24(vn->fd_fc_id);
+ frport->rdata.ids.port_name =
+ get_unaligned_be64(&vn->fd_wwpn);
break;
case FIP_DT_FC4F:
if (dlen != sizeof(struct fip_fc4_feat))
@@ -2750,10 +2748,7 @@ static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *fip, struct sk_buff *skb)
{
struct fip_header *fiph;
enum fip_vn2vn_subcode sub;
- struct {
- struct fc_rport_priv rdata;
- struct fcoe_rport frport;
- } buf;
+ struct fcoe_rport frport = { };
int rc, vlan_id = 0;
fiph = (struct fip_header *)skb->data;
@@ -2769,7 +2764,7 @@ static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *fip, struct sk_buff *skb)
goto drop;
}
- rc = fcoe_ctlr_vn_parse(fip, skb, &buf.rdata);
+ rc = fcoe_ctlr_vn_parse(fip, skb, &frport);
if (rc) {
LIBFCOE_FIP_DBG(fip, "vn_recv vn_parse error %d\n", rc);
goto drop;
@@ -2778,19 +2773,19 @@ static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *fip, struct sk_buff *skb)
mutex_lock(&fip->ctlr_mutex);
switch (sub) {
case FIP_SC_VN_PROBE_REQ:
- fcoe_ctlr_vn_probe_req(fip, &buf.rdata);
+ fcoe_ctlr_vn_probe_req(fip, &frport.rdata);
break;
case FIP_SC_VN_PROBE_REP:
- fcoe_ctlr_vn_probe_reply(fip, &buf.rdata);
+ fcoe_ctlr_vn_probe_reply(fip, &frport.rdata);
break;
case FIP_SC_VN_CLAIM_NOTIFY:
- fcoe_ctlr_vn_claim_notify(fip, &buf.rdata);
+ fcoe_ctlr_vn_claim_notify(fip, &frport.rdata);
break;
case FIP_SC_VN_CLAIM_REP:
- fcoe_ctlr_vn_claim_resp(fip, &buf.rdata);
+ fcoe_ctlr_vn_claim_resp(fip, &frport.rdata);
break;
case FIP_SC_VN_BEACON:
- fcoe_ctlr_vn_beacon(fip, &buf.rdata);
+ fcoe_ctlr_vn_beacon(fip, &frport.rdata);
break;
default:
LIBFCOE_FIP_DBG(fip, "vn_recv unknown subcode %d\n", sub);
@@ -2814,22 +2809,18 @@ static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *fip, struct sk_buff *skb)
*/
static int fcoe_ctlr_vlan_parse(struct fcoe_ctlr *fip,
struct sk_buff *skb,
- struct fc_rport_priv *rdata)
+ struct fcoe_rport *frport)
{
struct fip_header *fiph;
struct fip_desc *desc = NULL;
struct fip_mac_desc *macd = NULL;
struct fip_wwn_desc *wwn = NULL;
- struct fcoe_rport *frport;
size_t rlen;
size_t dlen;
u32 desc_mask = 0;
u32 dtype;
u8 sub;
- memset(rdata, 0, sizeof(*rdata) + sizeof(*frport));
- frport = fcoe_ctlr_rport(rdata);
-
fiph = (struct fip_header *)skb->data;
frport->flags = ntohs(fiph->fip_flags);
@@ -2883,7 +2874,8 @@ static int fcoe_ctlr_vlan_parse(struct fcoe_ctlr *fip,
if (dlen != sizeof(struct fip_wwn_desc))
goto len_err;
wwn = (struct fip_wwn_desc *)desc;
- rdata->ids.node_name = get_unaligned_be64(&wwn->fd_wwn);
+ frport->rdata.ids.node_name =
+ get_unaligned_be64(&wwn->fd_wwn);
break;
default:
LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x "
@@ -2994,22 +2986,19 @@ static int fcoe_ctlr_vlan_recv(struct fcoe_ctlr *fip, struct sk_buff *skb)
{
struct fip_header *fiph;
enum fip_vlan_subcode sub;
- struct {
- struct fc_rport_priv rdata;
- struct fcoe_rport frport;
- } buf;
+ struct fcoe_rport frport = { };
int rc;
fiph = (struct fip_header *)skb->data;
sub = fiph->fip_subcode;
- rc = fcoe_ctlr_vlan_parse(fip, skb, &buf.rdata);
+ rc = fcoe_ctlr_vlan_parse(fip, skb, &frport);
if (rc) {
LIBFCOE_FIP_DBG(fip, "vlan_recv vlan_parse error %d\n", rc);
goto drop;
}
mutex_lock(&fip->ctlr_mutex);
if (sub == FIP_SC_VL_REQ)
- fcoe_ctlr_vlan_disc_reply(fip, &buf.rdata);
+ fcoe_ctlr_vlan_disc_reply(fip, &frport.rdata);
mutex_unlock(&fip->ctlr_mutex);
drop:
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index 3d51a93..90a7485 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -140,6 +140,7 @@ EXPORT_SYMBOL(fc_rport_lookup);
struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, u32 port_id)
{
struct fc_rport_priv *rdata;
+ size_t rport_priv_size = sizeof(*rdata);
lockdep_assert_held(&lport->disc.disc_mutex);
@@ -147,7 +148,9 @@ struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, u32 port_id)
if (rdata)
return rdata;
- rdata = kzalloc(sizeof(*rdata) + lport->rport_priv_size, GFP_KERNEL);
+ if (lport->rport_priv_size > 0)
+ rport_priv_size = lport->rport_priv_size;
+ rdata = kzalloc(rport_priv_size, GFP_KERNEL);
if (!rdata)
return NULL;
diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c
index dd60573..643321f 100644
--- a/drivers/scsi/mac_scsi.c
+++ b/drivers/scsi/mac_scsi.c
@@ -3,6 +3,8 @@
*
* Copyright 1998, Michael Schmitz <mschmitz@lbl.gov>
*
+ * Copyright 2019 Finn Thain
+ *
* derived in part from:
*/
/*
@@ -11,6 +13,7 @@
* Copyright 1995, Russell King
*/
+#include <linux/delay.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/ioport.h>
@@ -52,7 +55,7 @@ static int setup_cmd_per_lun = -1;
module_param(setup_cmd_per_lun, int, 0);
static int setup_sg_tablesize = -1;
module_param(setup_sg_tablesize, int, 0);
-static int setup_use_pdma = -1;
+static int setup_use_pdma = 512;
module_param(setup_use_pdma, int, 0);
static int setup_hostid = -1;
module_param(setup_hostid, int, 0);
@@ -89,101 +92,217 @@ static int __init mac_scsi_setup(char *str)
__setup("mac5380=", mac_scsi_setup);
#endif /* !MODULE */
-/* Pseudo DMA asm originally by Ove Edlund */
+/*
+ * According to "Inside Macintosh: Devices", Mac OS requires disk drivers to
+ * specify the number of bytes between the delays expected from a SCSI target.
+ * This allows the operating system to "prevent bus errors when a target fails
+ * to deliver the next byte within the processor bus error timeout period."
+ * Linux SCSI drivers lack knowledge of the timing behaviour of SCSI targets
+ * so bus errors are unavoidable.
+ *
+ * If a MOVE.B instruction faults, we assume that zero bytes were transferred
+ * and simply retry. That assumption probably depends on target behaviour but
+ * seems to hold up okay. The NOP provides synchronization: without it the
+ * fault can sometimes occur after the program counter has moved past the
+ * offending instruction. Post-increment addressing can't be used.
+ */
-#define CP_IO_TO_MEM(s,d,n) \
-__asm__ __volatile__ \
- (" cmp.w #4,%2\n" \
- " bls 8f\n" \
- " move.w %1,%%d0\n" \
- " neg.b %%d0\n" \
- " and.w #3,%%d0\n" \
- " sub.w %%d0,%2\n" \
- " bra 2f\n" \
- " 1: move.b (%0),(%1)+\n" \
- " 2: dbf %%d0,1b\n" \
- " move.w %2,%%d0\n" \
- " lsr.w #5,%%d0\n" \
- " bra 4f\n" \
- " 3: move.l (%0),(%1)+\n" \
- "31: move.l (%0),(%1)+\n" \
- "32: move.l (%0),(%1)+\n" \
- "33: move.l (%0),(%1)+\n" \
- "34: move.l (%0),(%1)+\n" \
- "35: move.l (%0),(%1)+\n" \
- "36: move.l (%0),(%1)+\n" \
- "37: move.l (%0),(%1)+\n" \
- " 4: dbf %%d0,3b\n" \
- " move.w %2,%%d0\n" \
- " lsr.w #2,%%d0\n" \
- " and.w #7,%%d0\n" \
- " bra 6f\n" \
- " 5: move.l (%0),(%1)+\n" \
- " 6: dbf %%d0,5b\n" \
- " and.w #3,%2\n" \
- " bra 8f\n" \
- " 7: move.b (%0),(%1)+\n" \
- " 8: dbf %2,7b\n" \
- " moveq.l #0, %2\n" \
- " 9: \n" \
- ".section .fixup,\"ax\"\n" \
- " .even\n" \
- "91: moveq.l #1, %2\n" \
- " jra 9b\n" \
- "94: moveq.l #4, %2\n" \
- " jra 9b\n" \
- ".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n" \
- " .long 1b,91b\n" \
- " .long 3b,94b\n" \
- " .long 31b,94b\n" \
- " .long 32b,94b\n" \
- " .long 33b,94b\n" \
- " .long 34b,94b\n" \
- " .long 35b,94b\n" \
- " .long 36b,94b\n" \
- " .long 37b,94b\n" \
- " .long 5b,94b\n" \
- " .long 7b,91b\n" \
- ".previous" \
- : "=a"(s), "=a"(d), "=d"(n) \
- : "0"(s), "1"(d), "2"(n) \
- : "d0")
+#define MOVE_BYTE(operands) \
+ asm volatile ( \
+ "1: moveb " operands " \n" \
+ "11: nop \n" \
+ " addq #1,%0 \n" \
+ " subq #1,%1 \n" \
+ "40: \n" \
+ " \n" \
+ ".section .fixup,\"ax\" \n" \
+ ".even \n" \
+ "90: movel #1, %2 \n" \
+ " jra 40b \n" \
+ ".previous \n" \
+ " \n" \
+ ".section __ex_table,\"a\" \n" \
+ ".align 4 \n" \
+ ".long 1b,90b \n" \
+ ".long 11b,90b \n" \
+ ".previous \n" \
+ : "+a" (addr), "+r" (n), "+r" (result) : "a" (io))
+
+/*
+ * If a MOVE.W (or MOVE.L) instruction faults, it cannot be retried because
+ * the residual byte count would be uncertain. In that situation the MOVE_WORD
+ * macro clears n in the fixup section to abort the transfer.
+ */
+
+#define MOVE_WORD(operands) \
+ asm volatile ( \
+ "1: movew " operands " \n" \
+ "11: nop \n" \
+ " subq #2,%1 \n" \
+ "40: \n" \
+ " \n" \
+ ".section .fixup,\"ax\" \n" \
+ ".even \n" \
+ "90: movel #0, %1 \n" \
+ " movel #2, %2 \n" \
+ " jra 40b \n" \
+ ".previous \n" \
+ " \n" \
+ ".section __ex_table,\"a\" \n" \
+ ".align 4 \n" \
+ ".long 1b,90b \n" \
+ ".long 11b,90b \n" \
+ ".previous \n" \
+ : "+a" (addr), "+r" (n), "+r" (result) : "a" (io))
+
+#define MOVE_16_WORDS(operands) \
+ asm volatile ( \
+ "1: movew " operands " \n" \
+ "2: movew " operands " \n" \
+ "3: movew " operands " \n" \
+ "4: movew " operands " \n" \
+ "5: movew " operands " \n" \
+ "6: movew " operands " \n" \
+ "7: movew " operands " \n" \
+ "8: movew " operands " \n" \
+ "9: movew " operands " \n" \
+ "10: movew " operands " \n" \
+ "11: movew " operands " \n" \
+ "12: movew " operands " \n" \
+ "13: movew " operands " \n" \
+ "14: movew " operands " \n" \
+ "15: movew " operands " \n" \
+ "16: movew " operands " \n" \
+ "17: nop \n" \
+ " subl #32,%1 \n" \
+ "40: \n" \
+ " \n" \
+ ".section .fixup,\"ax\" \n" \
+ ".even \n" \
+ "90: movel #0, %1 \n" \
+ " movel #2, %2 \n" \
+ " jra 40b \n" \
+ ".previous \n" \
+ " \n" \
+ ".section __ex_table,\"a\" \n" \
+ ".align 4 \n" \
+ ".long 1b,90b \n" \
+ ".long 2b,90b \n" \
+ ".long 3b,90b \n" \
+ ".long 4b,90b \n" \
+ ".long 5b,90b \n" \
+ ".long 6b,90b \n" \
+ ".long 7b,90b \n" \
+ ".long 8b,90b \n" \
+ ".long 9b,90b \n" \
+ ".long 10b,90b \n" \
+ ".long 11b,90b \n" \
+ ".long 12b,90b \n" \
+ ".long 13b,90b \n" \
+ ".long 14b,90b \n" \
+ ".long 15b,90b \n" \
+ ".long 16b,90b \n" \
+ ".long 17b,90b \n" \
+ ".previous \n" \
+ : "+a" (addr), "+r" (n), "+r" (result) : "a" (io))
+
+#define MAC_PDMA_DELAY 32
+
+static inline int mac_pdma_recv(void __iomem *io, unsigned char *start, int n)
+{
+ unsigned char *addr = start;
+ int result = 0;
+
+ if (n >= 1) {
+ MOVE_BYTE("%3@,%0@");
+ if (result)
+ goto out;
+ }
+ if (n >= 1 && ((unsigned long)addr & 1)) {
+ MOVE_BYTE("%3@,%0@");
+ if (result)
+ goto out;
+ }
+ while (n >= 32)
+ MOVE_16_WORDS("%3@,%0@+");
+ while (n >= 2)
+ MOVE_WORD("%3@,%0@+");
+ if (result)
+ return start - addr; /* Negated to indicate uncertain length */
+ if (n == 1)
+ MOVE_BYTE("%3@,%0@");
+out:
+ return addr - start;
+}
+
+static inline int mac_pdma_send(unsigned char *start, void __iomem *io, int n)
+{
+ unsigned char *addr = start;
+ int result = 0;
+
+ if (n >= 1) {
+ MOVE_BYTE("%0@,%3@");
+ if (result)
+ goto out;
+ }
+ if (n >= 1 && ((unsigned long)addr & 1)) {
+ MOVE_BYTE("%0@,%3@");
+ if (result)
+ goto out;
+ }
+ while (n >= 32)
+ MOVE_16_WORDS("%0@+,%3@");
+ while (n >= 2)
+ MOVE_WORD("%0@+,%3@");
+ if (result)
+ return start - addr; /* Negated to indicate uncertain length */
+ if (n == 1)
+ MOVE_BYTE("%0@,%3@");
+out:
+ return addr - start;
+}
static inline int macscsi_pread(struct NCR5380_hostdata *hostdata,
unsigned char *dst, int len)
{
u8 __iomem *s = hostdata->pdma_io + (INPUT_DATA_REG << 4);
unsigned char *d = dst;
- int n = len;
- int transferred;
+
+ hostdata->pdma_residual = len;
while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG,
BASR_DRQ | BASR_PHASE_MATCH,
BASR_DRQ | BASR_PHASE_MATCH, HZ / 64)) {
- CP_IO_TO_MEM(s, d, n);
+ int bytes;
- transferred = d - dst - n;
- hostdata->pdma_residual = len - transferred;
+ bytes = mac_pdma_recv(s, d, min(hostdata->pdma_residual, 512));
- /* No bus error. */
- if (n == 0)
+ if (bytes > 0) {
+ d += bytes;
+ hostdata->pdma_residual -= bytes;
+ }
+
+ if (hostdata->pdma_residual == 0)
return 0;
- /* Target changed phase early? */
if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ,
- BUS_AND_STATUS_REG, BASR_ACK, BASR_ACK, HZ / 64) < 0)
- scmd_printk(KERN_ERR, hostdata->connected,
+ BUS_AND_STATUS_REG, BASR_ACK,
+ BASR_ACK, HZ / 64) < 0)
+ scmd_printk(KERN_DEBUG, hostdata->connected,
"%s: !REQ and !ACK\n", __func__);
if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))
return 0;
+ if (bytes == 0)
+ udelay(MAC_PDMA_DELAY);
+
+ if (bytes >= 0)
+ continue;
+
dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host,
- "%s: bus error (%d/%d)\n", __func__, transferred, len);
+ "%s: bus error (%d/%d)\n", __func__, d - dst, len);
NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
- d = dst + transferred;
- n = len - transferred;
+ return -1;
}
scmd_printk(KERN_ERR, hostdata->connected,
@@ -192,93 +311,27 @@ static inline int macscsi_pread(struct NCR5380_hostdata *hostdata,
return -1;
}
-
-#define CP_MEM_TO_IO(s,d,n) \
-__asm__ __volatile__ \
- (" cmp.w #4,%2\n" \
- " bls 8f\n" \
- " move.w %0,%%d0\n" \
- " neg.b %%d0\n" \
- " and.w #3,%%d0\n" \
- " sub.w %%d0,%2\n" \
- " bra 2f\n" \
- " 1: move.b (%0)+,(%1)\n" \
- " 2: dbf %%d0,1b\n" \
- " move.w %2,%%d0\n" \
- " lsr.w #5,%%d0\n" \
- " bra 4f\n" \
- " 3: move.l (%0)+,(%1)\n" \
- "31: move.l (%0)+,(%1)\n" \
- "32: move.l (%0)+,(%1)\n" \
- "33: move.l (%0)+,(%1)\n" \
- "34: move.l (%0)+,(%1)\n" \
- "35: move.l (%0)+,(%1)\n" \
- "36: move.l (%0)+,(%1)\n" \
- "37: move.l (%0)+,(%1)\n" \
- " 4: dbf %%d0,3b\n" \
- " move.w %2,%%d0\n" \
- " lsr.w #2,%%d0\n" \
- " and.w #7,%%d0\n" \
- " bra 6f\n" \
- " 5: move.l (%0)+,(%1)\n" \
- " 6: dbf %%d0,5b\n" \
- " and.w #3,%2\n" \
- " bra 8f\n" \
- " 7: move.b (%0)+,(%1)\n" \
- " 8: dbf %2,7b\n" \
- " moveq.l #0, %2\n" \
- " 9: \n" \
- ".section .fixup,\"ax\"\n" \
- " .even\n" \
- "91: moveq.l #1, %2\n" \
- " jra 9b\n" \
- "94: moveq.l #4, %2\n" \
- " jra 9b\n" \
- ".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n" \
- " .long 1b,91b\n" \
- " .long 3b,94b\n" \
- " .long 31b,94b\n" \
- " .long 32b,94b\n" \
- " .long 33b,94b\n" \
- " .long 34b,94b\n" \
- " .long 35b,94b\n" \
- " .long 36b,94b\n" \
- " .long 37b,94b\n" \
- " .long 5b,94b\n" \
- " .long 7b,91b\n" \
- ".previous" \
- : "=a"(s), "=a"(d), "=d"(n) \
- : "0"(s), "1"(d), "2"(n) \
- : "d0")
-
static inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata,
unsigned char *src, int len)
{
unsigned char *s = src;
u8 __iomem *d = hostdata->pdma_io + (OUTPUT_DATA_REG << 4);
- int n = len;
- int transferred;
+
+ hostdata->pdma_residual = len;
while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG,
BASR_DRQ | BASR_PHASE_MATCH,
BASR_DRQ | BASR_PHASE_MATCH, HZ / 64)) {
- CP_MEM_TO_IO(s, d, n);
+ int bytes;
- transferred = s - src - n;
- hostdata->pdma_residual = len - transferred;
+ bytes = mac_pdma_send(s, d, min(hostdata->pdma_residual, 512));
- /* Target changed phase early? */
- if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ,
- BUS_AND_STATUS_REG, BASR_ACK, BASR_ACK, HZ / 64) < 0)
- scmd_printk(KERN_ERR, hostdata->connected,
- "%s: !REQ and !ACK\n", __func__);
- if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))
- return 0;
+ if (bytes > 0) {
+ s += bytes;
+ hostdata->pdma_residual -= bytes;
+ }
- /* No bus error. */
- if (n == 0) {
+ if (hostdata->pdma_residual == 0) {
if (NCR5380_poll_politely(hostdata, TARGET_COMMAND_REG,
TCR_LAST_BYTE_SENT,
TCR_LAST_BYTE_SENT, HZ / 64) < 0)
@@ -287,17 +340,29 @@ static inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata,
return 0;
}
+ if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ,
+ BUS_AND_STATUS_REG, BASR_ACK,
+ BASR_ACK, HZ / 64) < 0)
+ scmd_printk(KERN_DEBUG, hostdata->connected,
+ "%s: !REQ and !ACK\n", __func__);
+ if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))
+ return 0;
+
+ if (bytes == 0)
+ udelay(MAC_PDMA_DELAY);
+
+ if (bytes >= 0)
+ continue;
+
dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host,
- "%s: bus error (%d/%d)\n", __func__, transferred, len);
+ "%s: bus error (%d/%d)\n", __func__, s - src, len);
NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
- s = src + transferred;
- n = len - transferred;
+ return -1;
}
scmd_printk(KERN_ERR, hostdata->connected,
"%s: phase mismatch or !DRQ\n", __func__);
NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host);
-
return -1;
}
@@ -305,7 +370,7 @@ static int macscsi_dma_xfer_len(struct NCR5380_hostdata *hostdata,
struct scsi_cmnd *cmd)
{
if (hostdata->flags & FLAG_NO_PSEUDO_DMA ||
- cmd->SCp.this_residual < 16)
+ cmd->SCp.this_residual < setup_use_pdma)
return 0;
return cmd->SCp.this_residual;
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index acb503e..e0c8722 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -5862,7 +5862,8 @@ megasas_get_target_prop(struct megasas_instance *instance,
int ret;
struct megasas_cmd *cmd;
struct megasas_dcmd_frame *dcmd;
- u16 targetId = (sdev->channel % 2) + sdev->id;
+ u16 targetId = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) +
+ sdev->id;
cmd = megasas_get_cmd(instance);
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c
index 8776330..d2ab520 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -2565,12 +2565,14 @@ _base_config_dma_addressing(struct MPT3SAS_ADAPTER *ioc, struct pci_dev *pdev)
{
struct sysinfo s;
u64 consistent_dma_mask;
+ /* Set 63 bit DMA mask for all SAS3 and SAS35 controllers */
+ int dma_mask = (ioc->hba_mpi_version_belonged > MPI2_VERSION) ? 63 : 64;
if (ioc->is_mcpu_endpoint)
goto try_32bit;
if (ioc->dma_mask)
- consistent_dma_mask = DMA_BIT_MASK(64);
+ consistent_dma_mask = DMA_BIT_MASK(dma_mask);
else
consistent_dma_mask = DMA_BIT_MASK(32);
@@ -2578,11 +2580,11 @@ _base_config_dma_addressing(struct MPT3SAS_ADAPTER *ioc, struct pci_dev *pdev)
const uint64_t required_mask =
dma_get_required_mask(&pdev->dev);
if ((required_mask > DMA_BIT_MASK(32)) &&
- !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) &&
+ !pci_set_dma_mask(pdev, DMA_BIT_MASK(dma_mask)) &&
!pci_set_consistent_dma_mask(pdev, consistent_dma_mask)) {
ioc->base_add_sg_single = &_base_add_sg_single_64;
ioc->sge_size = sizeof(Mpi2SGESimple64_t);
- ioc->dma_mask = 64;
+ ioc->dma_mask = dma_mask;
goto out;
}
}
@@ -2609,7 +2611,7 @@ static int
_base_change_consistent_dma_mask(struct MPT3SAS_ADAPTER *ioc,
struct pci_dev *pdev)
{
- if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) {
+ if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(ioc->dma_mask))) {
if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))
return -ENODEV;
}
@@ -4545,7 +4547,7 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc)
total_sz += sz;
} while (ioc->rdpq_array_enable && (++i < ioc->reply_queue_count));
- if (ioc->dma_mask == 64) {
+ if (ioc->dma_mask > 32) {
if (_base_change_consistent_dma_mask(ioc, ioc->pdev) != 0) {
pr_warn(MPT3SAS_FMT
"no suitable consistent DMA mask for %s\n",
diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c
index 4de740d..763c762 100644
--- a/drivers/scsi/qedi/qedi_main.c
+++ b/drivers/scsi/qedi/qedi_main.c
@@ -955,6 +955,9 @@ static int qedi_find_boot_info(struct qedi_ctx *qedi,
if (!iscsi_is_session_online(cls_sess))
continue;
+ if (!sess->targetname)
+ continue;
+
if (pri_ctrl_flags) {
if (!strcmp(pri_tgt->iscsi_name, sess->targetname) &&
!strcmp(pri_tgt->ip_addr, ep_ip_addr)) {
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index ffc0d14..648c717 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -71,11 +71,11 @@ int scsi_init_sense_cache(struct Scsi_Host *shost)
struct kmem_cache *cache;
int ret = 0;
+ mutex_lock(&scsi_sense_cache_mutex);
cache = scsi_select_sense_cache(shost->unchecked_isa_dma);
if (cache)
- return 0;
+ goto exit;
- mutex_lock(&scsi_sense_cache_mutex);
if (shost->unchecked_isa_dma) {
scsi_sense_isadma_cache =
kmem_cache_create("scsi_sense_cache(DMA)",
@@ -91,7 +91,7 @@ int scsi_init_sense_cache(struct Scsi_Host *shost)
if (!scsi_sense_cache)
ret = -ENOMEM;
}
-
+ exit:
mutex_unlock(&scsi_sense_cache_mutex);
return ret;
}
@@ -3092,11 +3092,14 @@ scsi_device_quiesce(struct scsi_device *sdev)
*/
WARN_ON_ONCE(sdev->quiesced_by && sdev->quiesced_by != current);
- blk_set_preempt_only(q);
+ if (sdev->quiesced_by == current)
+ return 0;
+
+ blk_set_pm_only(q);
blk_mq_freeze_queue(q);
/*
- * Ensure that the effect of blk_set_preempt_only() will be visible
+ * Ensure that the effect of blk_set_pm_only() will be visible
* for percpu_ref_tryget() callers that occur after the queue
* unfreeze even if the queue was already frozen before this function
* was called. See also https://lwn.net/Articles/573497/.
@@ -3109,7 +3112,7 @@ scsi_device_quiesce(struct scsi_device *sdev)
if (err == 0)
sdev->quiesced_by = current;
else
- blk_clear_preempt_only(q);
+ blk_clear_pm_only(q);
mutex_unlock(&sdev->state_mutex);
return err;
@@ -3132,8 +3135,10 @@ void scsi_device_resume(struct scsi_device *sdev)
* device deleted during suspend)
*/
mutex_lock(&sdev->state_mutex);
- sdev->quiesced_by = NULL;
- blk_clear_preempt_only(sdev->request_queue);
+ if (sdev->quiesced_by) {
+ sdev->quiesced_by = NULL;
+ blk_clear_pm_only(sdev->request_queue);
+ }
if (sdev->sdev_state == SDEV_QUIESCE)
scsi_device_set_state(sdev, SDEV_RUNNING);
mutex_unlock(&sdev->state_mutex);
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index f7b612f..ec0a589 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1806,7 +1806,7 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up)
ret = ufshcd_uic_hibern8_enter(hba);
if (ret)
/* link will be bad state so no need to scale_up_gear */
- return ret;
+ goto clk_scaling_unprepare;
ufshcd_custom_cmd_log(hba, "Hibern8-entered");
}
@@ -1819,7 +1819,7 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up)
ret = ufshcd_uic_hibern8_exit(hba);
if (ret)
/* link will be bad state so no need to scale_up_gear */
- return ret;
+ goto clk_scaling_unprepare;
ufshcd_custom_cmd_log(hba, "Hibern8-Exited");
}
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index 93e8457..0e754ff 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -2036,10 +2036,6 @@ static int ngd_slim_remove(struct platform_device *pdev)
struct msm_slim_ctrl *dev = platform_get_drvdata(pdev);
ngd_slim_enable(dev, false);
- if (!IS_ERR_OR_NULL(dev->iommu_desc.iommu_map)) {
- __depr_arm_iommu_detach_device(dev->iommu_desc.cb_dev);
- __depr_arm_iommu_release_mapping(dev->iommu_desc.iommu_map);
- }
if (dev->sysfs_created)
sysfs_remove_file(&dev->dev->kobj,
&dev_attr_debug_mask.attr);
diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h
index 5baabc3..cd5b1ca 100644
--- a/drivers/slimbus/slim-msm.h
+++ b/drivers/slimbus/slim-msm.h
@@ -257,7 +257,6 @@ struct msm_slim_bulk_wr {
struct msm_slim_iommu {
struct device *cb_dev;
- struct dma_iommu_mapping *iommu_map;
bool s1_bypass;
};
diff --git a/drivers/soc/bcm/brcmstb/biuctrl.c b/drivers/soc/bcm/brcmstb/biuctrl.c
index 6d89ebf..20b63be 100644
--- a/drivers/soc/bcm/brcmstb/biuctrl.c
+++ b/drivers/soc/bcm/brcmstb/biuctrl.c
@@ -56,7 +56,7 @@ static inline void cbc_writel(u32 val, int reg)
if (offset == -1)
return;
- writel_relaxed(val, cpubiuctrl_base + offset);
+ writel(val, cpubiuctrl_base + offset);
}
enum cpubiuctrl_regs {
@@ -246,7 +246,9 @@ static int __init brcmstb_biuctrl_init(void)
if (!np)
return 0;
- setup_hifcpubiuctrl_regs(np);
+ ret = setup_hifcpubiuctrl_regs(np);
+ if (ret)
+ return ret;
ret = mcp_write_pairing_set();
if (ret) {
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 1a36bc8..1c5acda 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -24,6 +24,16 @@
helps reduce power consumption during idle mode of the system.
If unsure, say N
+config BUG_ON_HW_MEM_ONLINE_FAIL
+ bool "Trigger a BUG when HW memory online fails"
+ depends on QCOM_MEM_OFFLINE
+ help
+ Select this option if kernel should BUG when the hardware
+ onlining of memory hotplug blocks fails. This helps to catch
+ online failures much quicker and avoids the later side effects
+ of such memory online failures.
+ If unsure, say N
+
config QCOM_GENI_SE
tristate "QCOM GENI Serial Engine Driver"
depends on ARCH_QCOM || COMPILE_TEST
diff --git a/drivers/soc/qcom/ddr_stats.c b/drivers/soc/qcom/ddr_stats.c
index cb10342..49b0209 100644
--- a/drivers/soc/qcom/ddr_stats.c
+++ b/drivers/soc/qcom/ddr_stats.c
@@ -18,9 +18,10 @@
#include <linux/uaccess.h>
#include <asm/arch_timer.h>
+#include <clocksource/arm_arch_timer.h>
+
#define MAGIC_KEY1 0xA1157A75
#define MAX_NUM_MODES 0x14
-#define MSM_ARCH_TIMER_FREQ 19200000
#define GET_PDATA_OF_ATTR(attr) \
(container_of(attr, struct ddr_stats_kobj_attr, ka)->pd)
@@ -48,10 +49,9 @@ struct ddr_stats_kobj_attr {
struct ddr_stats_platform_data *pd;
};
-static inline u64 get_time_in_msec(u64 counter)
+static u64 get_time_in_msec(u64 counter)
{
- do_div(counter, MSM_ARCH_TIMER_FREQ);
- counter *= MSEC_PER_SEC;
+ do_div(counter, (arch_timer_get_rate()/MSEC_PER_SEC));
return counter;
}
diff --git a/drivers/soc/qcom/mem-offline.c b/drivers/soc/qcom/mem-offline.c
index 4b0785a..82f0717 100644
--- a/drivers/soc/qcom/mem-offline.c
+++ b/drivers/soc/qcom/mem-offline.c
@@ -45,6 +45,8 @@ enum memory_states {
MAX_STATE,
};
+static enum memory_states *mem_sec_state;
+
static struct mem_offline_mailbox {
struct mbox_client cl;
struct mbox_chan *mbox;
@@ -134,6 +136,148 @@ static int aop_send_msg(unsigned long addr, bool online)
return (mbox_send_message(mailbox.mbox, &pkt) < 0);
}
+/*
+ * When offline_granule >= memory block size, this returns the number of
+ * sections in a offlineable segment.
+ * When offline_granule < memory block size, returns the sections_per_block.
+ */
+static unsigned long get_rounded_sections_per_segment(void)
+{
+
+ return max(((offline_granule * SZ_1M) / memory_block_size_bytes()) *
+ sections_per_block,
+ (unsigned long)sections_per_block);
+}
+
+static int send_msg(struct memory_notify *mn, bool online, int count)
+{
+ unsigned long segment_size = offline_granule * SZ_1M;
+ unsigned long start, base_sec_nr, sec_nr, sections_per_segment;
+ int ret, idx, i;
+
+ sections_per_segment = get_rounded_sections_per_segment();
+ sec_nr = pfn_to_section_nr(SECTION_ALIGN_DOWN(mn->start_pfn));
+ idx = (sec_nr - start_section_nr) / sections_per_segment;
+ base_sec_nr = start_section_nr + (idx * sections_per_segment);
+ start = section_nr_to_pfn(base_sec_nr);
+
+ for (i = 0; i < count; ++i) {
+ ret = aop_send_msg(__pfn_to_phys(start), online);
+ if (ret) {
+ pr_err("PASR: AOP %s request addr:0x%llx failed\n",
+ online ? "online" : "offline",
+ __pfn_to_phys(start));
+ goto undo;
+ }
+
+ start = __phys_to_pfn(__pfn_to_phys(start) + segment_size);
+ }
+
+ return 0;
+undo:
+ start = section_nr_to_pfn(base_sec_nr);
+ while (i-- > 0) {
+ int ret;
+
+ ret = aop_send_msg(__pfn_to_phys(start), !online);
+ if (ret)
+ panic("Failed to completely online/offline a hotpluggable segment. A quasi state of memblock can cause randomn system failures.");
+ start = __phys_to_pfn(__pfn_to_phys(start) + segment_size);
+ }
+
+ return ret;
+}
+
+static bool need_to_send_remote_request(struct memory_notify *mn,
+ enum memory_states request)
+{
+ int i, idx, cur_idx;
+ int base_sec_nr, sec_nr;
+ unsigned long sections_per_segment;
+
+ sections_per_segment = get_rounded_sections_per_segment();
+ sec_nr = pfn_to_section_nr(SECTION_ALIGN_DOWN(mn->start_pfn));
+ idx = (sec_nr - start_section_nr) / sections_per_segment;
+ cur_idx = (sec_nr - start_section_nr) / sections_per_block;
+ base_sec_nr = start_section_nr + (idx * sections_per_segment);
+
+ /*
+ * For MEM_OFFLINE, don't send the request if there are other online
+ * blocks in the segment.
+ * For MEM_ONLINE, don't send the request if there is already one
+ * online block in the segment.
+ */
+ if (request == MEMORY_OFFLINE || request == MEMORY_ONLINE) {
+ for (i = base_sec_nr;
+ i < (base_sec_nr + sections_per_segment);
+ i += sections_per_block) {
+ idx = (i - start_section_nr) / sections_per_block;
+ /* current operating block */
+ if (idx == cur_idx)
+ continue;
+ if (mem_sec_state[idx] == MEMORY_ONLINE)
+ goto out;
+ }
+ return true;
+ }
+out:
+ return false;
+}
+
+/*
+ * This returns the number of hotpluggable segments in a memory block.
+ */
+static int get_num_memblock_hotplug_segments(void)
+{
+ unsigned long segment_size = offline_granule * SZ_1M;
+ unsigned long block_size = memory_block_size_bytes();
+
+ if (segment_size < block_size) {
+ if (block_size % segment_size) {
+ pr_warn("PASR is unusable. Offline granule size should be in multiples for memory_block_size_bytes.\n");
+ return 0;
+ }
+ return block_size / segment_size;
+ }
+
+ return 1;
+}
+
+static int mem_change_refresh_state(struct memory_notify *mn,
+ enum memory_states state)
+{
+ int start = SECTION_ALIGN_DOWN(mn->start_pfn);
+ unsigned long sec_nr = pfn_to_section_nr(start);
+ bool online = (state == MEMORY_ONLINE) ? true : false;
+ unsigned long idx = (sec_nr - start_section_nr) / sections_per_block;
+ int ret, count;
+
+ if (mem_sec_state[idx] == state) {
+ /* we shouldn't be getting this request */
+ pr_warn("mem-offline: state of mem%d block already in %s state. Ignoring refresh state change request\n",
+ sec_nr, online ? "online" : "offline");
+ return 0;
+ }
+
+ count = get_num_memblock_hotplug_segments();
+ if (!count)
+ return -EINVAL;
+
+ if (!need_to_send_remote_request(mn, state))
+ goto out;
+
+ ret = send_msg(mn, online, count);
+ if (ret) {
+ /* online failures are critical failures */
+ if (online)
+ BUG_ON(IS_ENABLED(CONFIG_BUG_ON_HW_MEM_ONLINE_FAIL));
+ return -EINVAL;
+ }
+out:
+ mem_sec_state[idx] = state;
+ return 0;
+}
+
static int mem_event_callback(struct notifier_block *self,
unsigned long action, void *arg)
{
@@ -173,9 +317,9 @@ static int mem_event_callback(struct notifier_block *self,
idx) / sections_per_block].fail_count;
cur = ktime_get();
- if (aop_send_msg(__pfn_to_phys(start), true))
- pr_err("PASR: AOP online request addr:0x%llx failed\n",
- __pfn_to_phys(start));
+ if (mem_change_refresh_state(mn, MEMORY_ONLINE))
+ return NOTIFY_BAD;
+
if (!debug_pagealloc_enabled()) {
/* Create kernel page-tables */
create_pgtable_mapping(start_addr, end_addr);
@@ -201,9 +345,11 @@ static int mem_event_callback(struct notifier_block *self,
/* Clear kernel page-tables */
clear_pgtable_mapping(start_addr, end_addr);
}
- if (aop_send_msg(__pfn_to_phys(start), false))
- pr_err("PASR: AOP offline request addr:0x%llx failed\n",
- __pfn_to_phys(start));
+ mem_change_refresh_state(mn, MEMORY_OFFLINE);
+ /*
+ * Notifying that something went bad at this stage won't
+ * help since this is the last stage of memory hotplug.
+ */
delay = ktime_ms_delta(ktime_get(), cur);
record_stat(sec_nr, delay, MEMORY_OFFLINE);
@@ -214,9 +360,7 @@ static int mem_event_callback(struct notifier_block *self,
case MEM_CANCEL_ONLINE:
pr_info("mem-offline: MEM_CANCEL_ONLINE: start = 0x%llx end = 0x%llx\n",
start_addr, end_addr);
- if (aop_send_msg(__pfn_to_phys(start), false))
- pr_err("PASR: AOP online request addr:0x%llx failed\n",
- __pfn_to_phys(start));
+ mem_change_refresh_state(mn, MEMORY_OFFLINE);
break;
default:
break;
@@ -348,9 +492,6 @@ static struct attribute_group mem_attr_group = {
static int mem_sysfs_init(void)
{
- unsigned int total_blks = (end_section_nr - start_section_nr + 1) /
- sections_per_block;
-
if (start_section_nr == end_section_nr)
return -EINVAL;
@@ -361,11 +502,6 @@ static int mem_sysfs_init(void)
if (sysfs_create_group(kobj, &mem_attr_group))
kobject_put(kobj);
- mem_info = kzalloc(sizeof(*mem_info) * total_blks * MAX_STATE,
- GFP_KERNEL);
- if (!mem_info)
- return -ENOMEM;
-
return 0;
}
@@ -384,8 +520,9 @@ static int mem_parse_dt(struct platform_device *pdev)
return -EINVAL;
}
offline_granule = be32_to_cpup(val);
- if (!offline_granule && !(offline_granule & (offline_granule - 1)) &&
- offline_granule * SZ_1M < MIN_MEMORY_BLOCK_SIZE) {
+ if (!offline_granule || (offline_granule & (offline_granule - 1)) ||
+ ((offline_granule * SZ_1M < MIN_MEMORY_BLOCK_SIZE) &&
+ (MIN_MEMORY_BLOCK_SIZE % (offline_granule * SZ_1M)))) {
pr_err("mem-offine: invalid granule property\n");
return -EINVAL;
}
@@ -413,7 +550,8 @@ static struct notifier_block hotplug_memory_callback_nb = {
static int mem_offline_driver_probe(struct platform_device *pdev)
{
- int ret;
+ unsigned int total_blks;
+ int ret, i;
ret = mem_parse_dt(pdev);
if (ret)
@@ -426,16 +564,46 @@ static int mem_offline_driver_probe(struct platform_device *pdev)
if (ret > 0)
pr_err("mem-offline: !!ERROR!! Auto onlining some memory blocks failed. System could run with less RAM\n");
- if (mem_sysfs_init())
- return -ENODEV;
+ total_blks = (end_section_nr - start_section_nr + 1) /
+ sections_per_block;
+ mem_info = kcalloc(total_blks * MAX_STATE, sizeof(*mem_info),
+ GFP_KERNEL);
+ if (!mem_info)
+ return -ENOMEM;
+
+ mem_sec_state = kcalloc(total_blks, sizeof(*mem_sec_state), GFP_KERNEL);
+ if (!mem_sec_state) {
+ ret = -ENOMEM;
+ goto err_free_mem_info;
+ }
+
+ /* we assume that hardware state of mem blocks are online after boot */
+ for (i = 0; i < total_blks; i++)
+ mem_sec_state[i] = MEMORY_ONLINE;
+
+ if (mem_sysfs_init()) {
+ ret = -ENODEV;
+ goto err_free_mem_sec_state;
+ }
if (register_hotmemory_notifier(&hotplug_memory_callback_nb)) {
pr_err("mem-offline: Registering memory hotplug notifier failed\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_sysfs_remove_group;
}
pr_info("mem-offline: Added memory blocks ranging from mem%lu - mem%lu\n",
start_section_nr, end_section_nr);
+
return 0;
+
+err_sysfs_remove_group:
+ sysfs_remove_group(kobj, &mem_attr_group);
+ kobject_put(kobj);
+err_free_mem_sec_state:
+ kfree(mem_sec_state);
+err_free_mem_info:
+ kfree(mem_info);
+ return ret;
}
static const struct of_device_id mem_offline_match_table[] = {
diff --git a/drivers/soc/qcom/qtee_shmbridge.c b/drivers/soc/qcom/qtee_shmbridge.c
index 048c8b7..84b9de3 100644
--- a/drivers/soc/qcom/qtee_shmbridge.c
+++ b/drivers/soc/qcom/qtee_shmbridge.c
@@ -62,6 +62,8 @@
#define VM_PERM_R PERM_READ
#define VM_PERM_W PERM_WRITE
+#define SHMBRIDGE_E_NOT_SUPPORTED 4 /* SHMbridge is not implemented */
+
/* ns_vmids */
#define UPDATE_NS_VMIDS(ns_vmids, id) \
(((uint64_t)(ns_vmids) << VM_BITS) \
@@ -123,10 +125,12 @@ static int32_t qtee_shmbridge_enable(bool enable)
desc.arginfo = TZ_SHM_BRIDGE_ENABLE_PARAM_ID;
ret = scm_call2(TZ_SHM_BRIDGE_ENABLE, &desc);
- if (ret) {
+ if (ret || desc.ret[0]) {
pr_err("Failed to enable shmbridge, rsp = %lld, ret = %d\n",
desc.ret[0], ret);
- return ret;
+ if (ret == -EIO || desc.ret[0] == SHMBRIDGE_E_NOT_SUPPORTED)
+ pr_warn("shmbridge is not supported by this target\n");
+ return ret | desc.ret[0];
}
qtee_shmbridge_enabled = true;
pr_warn("shmbridge is enabled\n");
@@ -373,14 +377,11 @@ static int __init qtee_shmbridge_init(void)
mutex_init(&bridge_list_head.lock);
INIT_LIST_HEAD(&bridge_list_head.head);
- /* do not enable shm bridge mechanism for now*/
- ret = qtee_shmbridge_enable(false);
+ /* enable shm bridge mechanism */
+ ret = qtee_shmbridge_enable(true);
if (ret) {
- if (ret == -EIO) {
- /* keep the mem pool even shmbridge isn't supported */
- pr_warn("shmbridge feature is not supported\n");
- ret = 0;
- }
+ /* keep the mem pool and return if failed to enable bridge */
+ ret = 0;
goto exit;
}
diff --git a/drivers/soc/qcom/spss_utils.c b/drivers/soc/qcom/spss_utils.c
index af8c225..9472d4f 100644
--- a/drivers/soc/qcom/spss_utils.c
+++ b/drivers/soc/qcom/spss_utils.c
@@ -28,6 +28,7 @@
#include <linux/bitops.h> /* BIT(x) */
#include <linux/platform_device.h> /* platform_driver_register() */
#include <linux/of.h> /* of_property_count_strings() */
+#include <linux/of_address.h> /* of_address_to_resource() */
#include <linux/io.h> /* ioremap_nocache() */
#include <linux/notifier.h>
#include <linux/sizes.h> /* SZ_4K */
@@ -94,6 +95,10 @@ struct spss_utils_device {
/* Device State */
static struct spss_utils_device *spss_utils_dev;
+/* static functions declaration */
+static int spss_set_fw_cmac(u32 *cmac, size_t cmac_size);
+static int spss_get_pbl_calc_cmac(u32 *cmac, size_t cmac_size);
+
/*==========================================================================*/
/* Device Sysfs */
/*==========================================================================*/
@@ -390,6 +395,20 @@ static long spss_utils_ioctl(struct file *file,
memcpy(cmac_buf, data, sizeof(cmac_buf));
pr_info("cmac_buf: 0x%x,0x%x,0x%x,0x%x\n",
cmac_buf[0], cmac_buf[1], cmac_buf[2], cmac_buf[3]);
+
+ /*
+ * SPSS is loaded now by UEFI,
+ * so IAR callback is not being called on powerup by PIL.
+ * therefore read the spu pbl fw cmac from ioctl.
+ * The callback shall be called on spss SSR.
+ */
+ pr_info("read pbl cmac from shared memory\n");
+ spss_set_fw_cmac(cmac_buf, sizeof(cmac_buf));
+ spss_get_pbl_calc_cmac(pbl_cmac_buf, sizeof(pbl_cmac_buf));
+ if (memcmp(cmac_buf, pbl_cmac_buf, sizeof(cmac_buf)) != 0)
+ is_pbl_ce = true; /* cmacs not the same */
+ else
+ is_pbl_ce = false;
break;
default:
@@ -495,7 +514,8 @@ static int spss_parse_dt(struct device_node *node)
u32 spss_fuse4_bit = 0;
u32 spss_fuse4_mask = 0;
void __iomem *spss_fuse4_reg = NULL;
-
+ struct device_node *np;
+ struct resource r;
u32 val1 = 0;
u32 val2 = 0;
void __iomem *spss_emul_type_reg = NULL;
@@ -631,14 +651,25 @@ static int spss_parse_dt(struct device_node *node)
iounmap(spss_emul_type_reg);
/* PIL-SPSS area */
- ret = of_property_read_u32(node, "qcom,pil-addr",
- &pil_addr);
- if (ret < 0) {
- pr_err("can't get pil_addr\n");
- return -EFAULT;
+ np = of_parse_phandle(node, "pil-mem", 0);
+ if (!np) {
+ pr_err("no pil-mem entry, check pil-addr\n");
+ ret = of_property_read_u32(node, "qcom,pil-addr",
+ &pil_addr);
+ if (ret < 0) {
+ pr_err("can't get pil_addr\n");
+ return -EFAULT;
+ }
+ } else {
+ ret = of_address_to_resource(np, 0, &r);
+ of_node_put(np);
+ if (ret)
+ return ret;
+ pil_addr = (u32)r.start;
}
+
ret = of_property_read_u32(node, "qcom,pil-size",
- &pil_size);
+ &pil_size);
if (ret < 0) {
pr_err("can't get pil_size\n");
return -EFAULT;
@@ -717,24 +748,8 @@ static int spss_parse_dt(struct device_node *node)
return 0;
}
-static int spss_assign_mem_to_spss_and_hlos(phys_addr_t addr, size_t size)
-{
- int ret;
- int srcVM[1] = {VMID_HLOS};
- int destVM[2] = {VMID_HLOS, VMID_CP_SPSS_HLOS_SHARED};
- int destVMperm[2] = {PERM_READ | PERM_WRITE, PERM_READ | PERM_WRITE};
-
- ret = hyp_assign_phys(addr, size, srcVM, 1, destVM, destVMperm, 2);
- if (ret)
- pr_err("hyp_assign_phys() failed, addr [%pa] size [%zx] ret [%d]\n",
- &addr, size, ret);
-
- return ret;
-}
-
static int spss_set_fw_cmac(u32 *cmac, size_t cmac_size)
{
- int ret;
u8 __iomem *reg = NULL;
int i;
@@ -746,10 +761,6 @@ static int spss_set_fw_cmac(u32 *cmac, size_t cmac_size)
}
}
- ret = spss_assign_mem_to_spss_and_hlos(cmac_mem_addr, cmac_mem_size);
- if (ret)
- return ret;
-
pr_debug("pil_addr [0x%x]\n", pil_addr);
pr_debug("pil_size [0x%x]\n", pil_size);
pr_debug("cmac_mem [%pK]\n", cmac_mem);
@@ -762,9 +773,6 @@ static int spss_set_fw_cmac(u32 *cmac, size_t cmac_size)
}
reg += cmac_size;
- for (i = 0; i < cmac_size/4; i++)
- writel_relaxed(0, reg + i*sizeof(u32));
-
return 0;
}
diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index 0a8990e..a6e2581 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -651,8 +651,8 @@ static int intel_create_dai(struct sdw_cdns *cdns,
return -ENOMEM;
}
- dais[i].playback.channels_min = 1;
- dais[i].playback.channels_max = max_ch;
+ dais[i].capture.channels_min = 1;
+ dais[i].capture.channels_max = max_ch;
dais[i].capture.rates = SNDRV_PCM_RATE_48000;
dais[i].capture.formats = SNDRV_PCM_FMTBIT_S16_LE;
}
diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
index e5c7e1e..907a548 100644
--- a/drivers/soundwire/stream.c
+++ b/drivers/soundwire/stream.c
@@ -1236,9 +1236,7 @@ struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave,
}
for (i = 0; i < num_ports; i++) {
- dpn_prop = &dpn_prop[i];
-
- if (dpn_prop->num == port_num)
+ if (dpn_prop[i].num == port_num)
return &dpn_prop[i];
}
diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
index 25abf2d..eab27d4 100644
--- a/drivers/spi/spi-bcm2835.c
+++ b/drivers/spi/spi-bcm2835.c
@@ -554,7 +554,8 @@ static int bcm2835_spi_transfer_one(struct spi_master *master,
bcm2835_wr(bs, BCM2835_SPI_CLK, cdiv);
/* handle all the 3-wire mode */
- if ((spi->mode & SPI_3WIRE) && (tfr->rx_buf))
+ if (spi->mode & SPI_3WIRE && tfr->rx_buf &&
+ tfr->rx_buf != master->dummy_rx)
cs |= BCM2835_SPI_CS_REN;
else
cs &= ~BCM2835_SPI_CS_REN;
diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c
index 08ffe26..0f16e85 100644
--- a/drivers/staging/comedi/drivers/amplc_pci230.c
+++ b/drivers/staging/comedi/drivers/amplc_pci230.c
@@ -2330,7 +2330,8 @@ static irqreturn_t pci230_interrupt(int irq, void *d)
devpriv->intr_running = false;
spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags);
- comedi_handle_events(dev, s_ao);
+ if (s_ao)
+ comedi_handle_events(dev, s_ao);
comedi_handle_events(dev, s_ai);
return IRQ_HANDLED;
diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c
index 3be927f..e15e33e 100644
--- a/drivers/staging/comedi/drivers/dt282x.c
+++ b/drivers/staging/comedi/drivers/dt282x.c
@@ -557,7 +557,8 @@ static irqreturn_t dt282x_interrupt(int irq, void *d)
}
#endif
comedi_handle_events(dev, s);
- comedi_handle_events(dev, s_ao);
+ if (s_ao)
+ comedi_handle_events(dev, s_ao);
return IRQ_RETVAL(handled);
}
diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
index ecdd3d8..8549e80 100644
--- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
+++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c
@@ -1073,6 +1073,7 @@ static int port_switchdev_event(struct notifier_block *unused,
dev_hold(dev);
break;
default:
+ kfree(switchdev_work);
return NOTIFY_DONE;
}
diff --git a/drivers/staging/iio/cdc/ad7150.c b/drivers/staging/iio/cdc/ad7150.c
index d16084d..a354ce6 100644
--- a/drivers/staging/iio/cdc/ad7150.c
+++ b/drivers/staging/iio/cdc/ad7150.c
@@ -6,6 +6,7 @@
* Licensed under the GPL-2 or later.
*/
+#include <linux/bitfield.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/kernel.h>
@@ -130,7 +131,7 @@ static int ad7150_read_event_config(struct iio_dev *indio_dev,
{
int ret;
u8 threshtype;
- bool adaptive;
+ bool thrfixed;
struct ad7150_chip_info *chip = iio_priv(indio_dev);
ret = i2c_smbus_read_byte_data(chip->client, AD7150_CFG);
@@ -138,21 +139,23 @@ static int ad7150_read_event_config(struct iio_dev *indio_dev,
return ret;
threshtype = (ret >> 5) & 0x03;
- adaptive = !!(ret & 0x80);
+
+ /*check if threshold mode is fixed or adaptive*/
+ thrfixed = FIELD_GET(AD7150_CFG_FIX, ret);
switch (type) {
case IIO_EV_TYPE_MAG_ADAPTIVE:
if (dir == IIO_EV_DIR_RISING)
- return adaptive && (threshtype == 0x1);
- return adaptive && (threshtype == 0x0);
+ return !thrfixed && (threshtype == 0x1);
+ return !thrfixed && (threshtype == 0x0);
case IIO_EV_TYPE_THRESH_ADAPTIVE:
if (dir == IIO_EV_DIR_RISING)
- return adaptive && (threshtype == 0x3);
- return adaptive && (threshtype == 0x2);
+ return !thrfixed && (threshtype == 0x3);
+ return !thrfixed && (threshtype == 0x2);
case IIO_EV_TYPE_THRESH:
if (dir == IIO_EV_DIR_RISING)
- return !adaptive && (threshtype == 0x1);
- return !adaptive && (threshtype == 0x0);
+ return thrfixed && (threshtype == 0x1);
+ return thrfixed && (threshtype == 0x0);
default:
break;
}
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c
index 1269a98..13b890b 100644
--- a/drivers/staging/media/davinci_vpfe/vpfe_video.c
+++ b/drivers/staging/media/davinci_vpfe/vpfe_video.c
@@ -422,6 +422,9 @@ static int vpfe_open(struct file *file)
/* If decoder is not initialized. initialize it */
if (!video->initialized && vpfe_update_pipe_state(video)) {
mutex_unlock(&video->lock);
+ v4l2_fh_del(&handle->vfh);
+ v4l2_fh_exit(&handle->vfh);
+ kfree(handle);
return -ENODEV;
}
/* Increment device users counter */
diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
index c3ff7c3..2f490a4 100644
--- a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
+++ b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
@@ -141,10 +141,91 @@ static inline void handle_group_key(struct ieee_param *param,
}
}
-static noinline_for_stack char *translate_scan(struct _adapter *padapter,
- struct iw_request_info *info,
- struct wlan_network *pnetwork,
- char *start, char *stop)
+static noinline_for_stack char *translate_scan_wpa(struct iw_request_info *info,
+ struct wlan_network *pnetwork,
+ struct iw_event *iwe,
+ char *start, char *stop)
+{
+ /* parsing WPA/WPA2 IE */
+ u8 buf[MAX_WPA_IE_LEN];
+ u8 wpa_ie[255], rsn_ie[255];
+ u16 wpa_len = 0, rsn_len = 0;
+ int n, i;
+
+ r8712_get_sec_ie(pnetwork->network.IEs,
+ pnetwork->network.IELength, rsn_ie, &rsn_len,
+ wpa_ie, &wpa_len);
+ if (wpa_len > 0) {
+ memset(buf, 0, MAX_WPA_IE_LEN);
+ n = sprintf(buf, "wpa_ie=");
+ for (i = 0; i < wpa_len; i++) {
+ n += snprintf(buf + n, MAX_WPA_IE_LEN - n,
+ "%02x", wpa_ie[i]);
+ if (n >= MAX_WPA_IE_LEN)
+ break;
+ }
+ memset(iwe, 0, sizeof(*iwe));
+ iwe->cmd = IWEVCUSTOM;
+ iwe->u.data.length = (u16)strlen(buf);
+ start = iwe_stream_add_point(info, start, stop,
+ iwe, buf);
+ memset(iwe, 0, sizeof(*iwe));
+ iwe->cmd = IWEVGENIE;
+ iwe->u.data.length = (u16)wpa_len;
+ start = iwe_stream_add_point(info, start, stop,
+ iwe, wpa_ie);
+ }
+ if (rsn_len > 0) {
+ memset(buf, 0, MAX_WPA_IE_LEN);
+ n = sprintf(buf, "rsn_ie=");
+ for (i = 0; i < rsn_len; i++) {
+ n += snprintf(buf + n, MAX_WPA_IE_LEN - n,
+ "%02x", rsn_ie[i]);
+ if (n >= MAX_WPA_IE_LEN)
+ break;
+ }
+ memset(iwe, 0, sizeof(*iwe));
+ iwe->cmd = IWEVCUSTOM;
+ iwe->u.data.length = strlen(buf);
+ start = iwe_stream_add_point(info, start, stop,
+ iwe, buf);
+ memset(iwe, 0, sizeof(*iwe));
+ iwe->cmd = IWEVGENIE;
+ iwe->u.data.length = rsn_len;
+ start = iwe_stream_add_point(info, start, stop, iwe,
+ rsn_ie);
+ }
+
+ return start;
+}
+
+static noinline_for_stack char *translate_scan_wps(struct iw_request_info *info,
+ struct wlan_network *pnetwork,
+ struct iw_event *iwe,
+ char *start, char *stop)
+{
+ /* parsing WPS IE */
+ u8 wps_ie[512];
+ uint wps_ielen;
+
+ if (r8712_get_wps_ie(pnetwork->network.IEs,
+ pnetwork->network.IELength,
+ wps_ie, &wps_ielen)) {
+ if (wps_ielen > 2) {
+ iwe->cmd = IWEVGENIE;
+ iwe->u.data.length = (u16)wps_ielen;
+ start = iwe_stream_add_point(info, start, stop,
+ iwe, wps_ie);
+ }
+ }
+
+ return start;
+}
+
+static char *translate_scan(struct _adapter *padapter,
+ struct iw_request_info *info,
+ struct wlan_network *pnetwork,
+ char *start, char *stop)
{
struct iw_event iwe;
struct ieee80211_ht_cap *pht_capie;
@@ -257,73 +338,11 @@ static noinline_for_stack char *translate_scan(struct _adapter *padapter,
/* Check if we added any event */
if ((current_val - start) > iwe_stream_lcp_len(info))
start = current_val;
- /* parsing WPA/WPA2 IE */
- {
- u8 buf[MAX_WPA_IE_LEN];
- u8 wpa_ie[255], rsn_ie[255];
- u16 wpa_len = 0, rsn_len = 0;
- int n;
- r8712_get_sec_ie(pnetwork->network.IEs,
- pnetwork->network.IELength, rsn_ie, &rsn_len,
- wpa_ie, &wpa_len);
- if (wpa_len > 0) {
- memset(buf, 0, MAX_WPA_IE_LEN);
- n = sprintf(buf, "wpa_ie=");
- for (i = 0; i < wpa_len; i++) {
- n += snprintf(buf + n, MAX_WPA_IE_LEN - n,
- "%02x", wpa_ie[i]);
- if (n >= MAX_WPA_IE_LEN)
- break;
- }
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = (u16)strlen(buf);
- start = iwe_stream_add_point(info, start, stop,
- &iwe, buf);
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = (u16)wpa_len;
- start = iwe_stream_add_point(info, start, stop,
- &iwe, wpa_ie);
- }
- if (rsn_len > 0) {
- memset(buf, 0, MAX_WPA_IE_LEN);
- n = sprintf(buf, "rsn_ie=");
- for (i = 0; i < rsn_len; i++) {
- n += snprintf(buf + n, MAX_WPA_IE_LEN - n,
- "%02x", rsn_ie[i]);
- if (n >= MAX_WPA_IE_LEN)
- break;
- }
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = strlen(buf);
- start = iwe_stream_add_point(info, start, stop,
- &iwe, buf);
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = rsn_len;
- start = iwe_stream_add_point(info, start, stop, &iwe,
- rsn_ie);
- }
- }
+ start = translate_scan_wpa(info, pnetwork, &iwe, start, stop);
- { /* parsing WPS IE */
- u8 wps_ie[512];
- uint wps_ielen;
+ start = translate_scan_wps(info, pnetwork, &iwe, start, stop);
- if (r8712_get_wps_ie(pnetwork->network.IEs,
- pnetwork->network.IELength,
- wps_ie, &wps_ielen)) {
- if (wps_ielen > 2) {
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = (u16)wps_ielen;
- start = iwe_stream_add_point(info, start, stop,
- &iwe, wps_ie);
- }
- }
- }
/* Add quality statistics */
iwe.cmd = IWEVQUAL;
rssi = r8712_signal_scale_mapping(pnetwork->network.Rssi);
diff --git a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
index c04bdf0..4550828 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
@@ -342,16 +342,13 @@ static void buffer_cb(struct vchiq_mmal_instance *instance,
return;
} else if (length == 0) {
/* stream ended */
- if (buf) {
- /* this should only ever happen if the port is
- * disabled and there are buffers still queued
+ if (dev->capture.frame_count) {
+ /* empty buffer whilst capturing - expected to be an
+ * EOS, so grab another frame
*/
- vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
- pr_debug("Empty buffer");
- } else if (dev->capture.frame_count) {
- /* grab another frame */
if (is_capturing(dev)) {
- pr_debug("Grab another frame");
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "Grab another frame");
vchiq_mmal_port_parameter_set(
instance,
dev->capture.camera_port,
@@ -359,8 +356,14 @@ static void buffer_cb(struct vchiq_mmal_instance *instance,
&dev->capture.frame_count,
sizeof(dev->capture.frame_count));
}
+ if (vchiq_mmal_submit_buffer(instance, port, buf))
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "Failed to return EOS buffer");
} else {
- /* signal frame completion */
+ /* stopping streaming.
+ * return buffer, and signal frame completion
+ */
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
complete(&dev->capture.frame_cmplt);
}
} else {
@@ -582,6 +585,7 @@ static void stop_streaming(struct vb2_queue *vq)
int ret;
unsigned long timeout;
struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
+ struct vchiq_mmal_port *port = dev->capture.port;
v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p\n",
__func__, dev);
@@ -605,12 +609,6 @@ static void stop_streaming(struct vb2_queue *vq)
&dev->capture.frame_count,
sizeof(dev->capture.frame_count));
- /* wait for last frame to complete */
- timeout = wait_for_completion_timeout(&dev->capture.frame_cmplt, HZ);
- if (timeout == 0)
- v4l2_err(&dev->v4l2_dev,
- "timed out waiting for frame completion\n");
-
v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
"disabling connection\n");
@@ -625,6 +623,21 @@ static void stop_streaming(struct vb2_queue *vq)
ret);
}
+ /* wait for all buffers to be returned */
+ while (atomic_read(&port->buffers_with_vpu)) {
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "%s: Waiting for buffers to be returned - %d outstanding\n",
+ __func__, atomic_read(&port->buffers_with_vpu));
+ timeout = wait_for_completion_timeout(&dev->capture.frame_cmplt,
+ HZ);
+ if (timeout == 0) {
+ v4l2_err(&dev->v4l2_dev, "%s: Timeout waiting for buffers to be returned - %d outstanding\n",
+ __func__,
+ atomic_read(&port->buffers_with_vpu));
+ break;
+ }
+ }
+
if (disable_camera(dev) < 0)
v4l2_err(&dev->v4l2_dev, "Failed to disable camera\n");
}
diff --git a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
index 51e5b04..daa2b96 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
@@ -162,7 +162,8 @@ struct vchiq_mmal_instance {
void *bulk_scratch;
struct idr context_map;
- spinlock_t context_map_lock;
+ /* protect accesses to context_map */
+ struct mutex context_map_lock;
/* component to use next */
int component_idx;
@@ -185,10 +186,10 @@ get_msg_context(struct vchiq_mmal_instance *instance)
* that when we service the VCHI reply, we can look up what
* message is being replied to.
*/
- spin_lock(&instance->context_map_lock);
+ mutex_lock(&instance->context_map_lock);
handle = idr_alloc(&instance->context_map, msg_context,
0, 0, GFP_KERNEL);
- spin_unlock(&instance->context_map_lock);
+ mutex_unlock(&instance->context_map_lock);
if (handle < 0) {
kfree(msg_context);
@@ -212,9 +213,9 @@ release_msg_context(struct mmal_msg_context *msg_context)
{
struct vchiq_mmal_instance *instance = msg_context->instance;
- spin_lock(&instance->context_map_lock);
+ mutex_lock(&instance->context_map_lock);
idr_remove(&instance->context_map, msg_context->handle);
- spin_unlock(&instance->context_map_lock);
+ mutex_unlock(&instance->context_map_lock);
kfree(msg_context);
}
@@ -240,6 +241,8 @@ static void buffer_work_cb(struct work_struct *work)
struct mmal_msg_context *msg_context =
container_of(work, struct mmal_msg_context, u.bulk.work);
+ atomic_dec(&msg_context->u.bulk.port->buffers_with_vpu);
+
msg_context->u.bulk.port->buffer_cb(msg_context->u.bulk.instance,
msg_context->u.bulk.port,
msg_context->u.bulk.status,
@@ -288,8 +291,6 @@ static int bulk_receive(struct vchiq_mmal_instance *instance,
/* store length */
msg_context->u.bulk.buffer_used = rd_len;
- msg_context->u.bulk.mmal_flags =
- msg->u.buffer_from_host.buffer_header.flags;
msg_context->u.bulk.dts = msg->u.buffer_from_host.buffer_header.dts;
msg_context->u.bulk.pts = msg->u.buffer_from_host.buffer_header.pts;
@@ -380,6 +381,8 @@ buffer_from_host(struct vchiq_mmal_instance *instance,
/* initialise work structure ready to schedule callback */
INIT_WORK(&msg_context->u.bulk.work, buffer_work_cb);
+ atomic_inc(&port->buffers_with_vpu);
+
/* prep the buffer from host message */
memset(&m, 0xbc, sizeof(m)); /* just to make debug clearer */
@@ -448,6 +451,9 @@ static void buffer_to_host_cb(struct vchiq_mmal_instance *instance,
return;
}
+ msg_context->u.bulk.mmal_flags =
+ msg->u.buffer_from_host.buffer_header.flags;
+
if (msg->h.status != MMAL_MSG_STATUS_SUCCESS) {
/* message reception had an error */
pr_warn("error %d in reply\n", msg->h.status);
@@ -1324,16 +1330,6 @@ static int port_enable(struct vchiq_mmal_instance *instance,
if (port->enabled)
return 0;
- /* ensure there are enough buffers queued to cover the buffer headers */
- if (port->buffer_cb) {
- hdr_count = 0;
- list_for_each(buf_head, &port->buffers) {
- hdr_count++;
- }
- if (hdr_count < port->current_buffer.num)
- return -ENOSPC;
- }
-
ret = port_action_port(instance, port,
MMAL_MSG_PORT_ACTION_TYPE_ENABLE);
if (ret)
@@ -1854,7 +1850,7 @@ int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance)
instance->bulk_scratch = vmalloc(PAGE_SIZE);
- spin_lock_init(&instance->context_map_lock);
+ mutex_init(&instance->context_map_lock);
idr_init_base(&instance->context_map, 1);
params.callback_param = instance;
diff --git a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h
index 22b839e..b0ee171 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h
+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h
@@ -71,6 +71,9 @@ struct vchiq_mmal_port {
struct list_head buffers;
/* lock to serialise adding and removing buffers from list */
spinlock_t slock;
+
+ /* Count of buffers the VPU has yet to return */
+ atomic_t buffers_with_vpu;
/* callback on buffer completion */
vchiq_mmal_buffer_cb buffer_cb;
/* callback context */
diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c
index ccafcc2..70433f7 100644
--- a/drivers/staging/vt6656/main_usb.c
+++ b/drivers/staging/vt6656/main_usb.c
@@ -402,16 +402,19 @@ static void vnt_free_int_bufs(struct vnt_private *priv)
kfree(priv->int_buf.data_buf);
}
-static bool vnt_alloc_bufs(struct vnt_private *priv)
+static int vnt_alloc_bufs(struct vnt_private *priv)
{
+ int ret = 0;
struct vnt_usb_send_context *tx_context;
struct vnt_rcb *rcb;
int ii;
for (ii = 0; ii < priv->num_tx_context; ii++) {
tx_context = kmalloc(sizeof(*tx_context), GFP_KERNEL);
- if (!tx_context)
+ if (!tx_context) {
+ ret = -ENOMEM;
goto free_tx;
+ }
priv->tx_context[ii] = tx_context;
tx_context->priv = priv;
@@ -419,16 +422,20 @@ static bool vnt_alloc_bufs(struct vnt_private *priv)
/* allocate URBs */
tx_context->urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!tx_context->urb)
+ if (!tx_context->urb) {
+ ret = -ENOMEM;
goto free_tx;
+ }
tx_context->in_use = false;
}
for (ii = 0; ii < priv->num_rcb; ii++) {
priv->rcb[ii] = kzalloc(sizeof(*priv->rcb[ii]), GFP_KERNEL);
- if (!priv->rcb[ii])
+ if (!priv->rcb[ii]) {
+ ret = -ENOMEM;
goto free_rx_tx;
+ }
rcb = priv->rcb[ii];
@@ -436,39 +443,46 @@ static bool vnt_alloc_bufs(struct vnt_private *priv)
/* allocate URBs */
rcb->urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!rcb->urb)
+ if (!rcb->urb) {
+ ret = -ENOMEM;
goto free_rx_tx;
+ }
rcb->skb = dev_alloc_skb(priv->rx_buf_sz);
- if (!rcb->skb)
+ if (!rcb->skb) {
+ ret = -ENOMEM;
goto free_rx_tx;
+ }
rcb->in_use = false;
/* submit rx urb */
- if (vnt_submit_rx_urb(priv, rcb))
+ ret = vnt_submit_rx_urb(priv, rcb);
+ if (ret)
goto free_rx_tx;
}
priv->interrupt_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!priv->interrupt_urb)
- goto free_rx_tx;
-
- priv->int_buf.data_buf = kmalloc(MAX_INTERRUPT_SIZE, GFP_KERNEL);
- if (!priv->int_buf.data_buf) {
- usb_free_urb(priv->interrupt_urb);
+ if (!priv->interrupt_urb) {
+ ret = -ENOMEM;
goto free_rx_tx;
}
- return true;
+ priv->int_buf.data_buf = kmalloc(MAX_INTERRUPT_SIZE, GFP_KERNEL);
+ if (!priv->int_buf.data_buf) {
+ ret = -ENOMEM;
+ goto free_rx_tx_urb;
+ }
+ return 0;
+
+free_rx_tx_urb:
+ usb_free_urb(priv->interrupt_urb);
free_rx_tx:
vnt_free_rx_bufs(priv);
-
free_tx:
vnt_free_tx_bufs(priv);
-
- return false;
+ return ret;
}
static void vnt_tx_80211(struct ieee80211_hw *hw,
diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c
index 4e680d7..e2fa3a3 100644
--- a/drivers/target/iscsi/iscsi_target_auth.c
+++ b/drivers/target/iscsi/iscsi_target_auth.c
@@ -89,6 +89,12 @@ static int chap_check_algorithm(const char *a_str)
return CHAP_DIGEST_UNKNOWN;
}
+static void chap_close(struct iscsi_conn *conn)
+{
+ kfree(conn->auth_protocol);
+ conn->auth_protocol = NULL;
+}
+
static struct iscsi_chap *chap_server_open(
struct iscsi_conn *conn,
struct iscsi_node_auth *auth,
@@ -126,7 +132,7 @@ static struct iscsi_chap *chap_server_open(
case CHAP_DIGEST_UNKNOWN:
default:
pr_err("Unsupported CHAP_A value\n");
- kfree(conn->auth_protocol);
+ chap_close(conn);
return NULL;
}
@@ -141,19 +147,13 @@ static struct iscsi_chap *chap_server_open(
* Generate Challenge.
*/
if (chap_gen_challenge(conn, 1, aic_str, aic_len) < 0) {
- kfree(conn->auth_protocol);
+ chap_close(conn);
return NULL;
}
return chap;
}
-static void chap_close(struct iscsi_conn *conn)
-{
- kfree(conn->auth_protocol);
- conn->auth_protocol = NULL;
-}
-
static int chap_server_compute_md5(
struct iscsi_conn *conn,
struct iscsi_node_auth *auth,
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 3f779d2..aa4de69 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -1869,13 +1869,13 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
status = serial_port_in(port, UART_LSR);
- if (status & (UART_LSR_DR | UART_LSR_BI) &&
- iir & UART_IIR_RDI) {
+ if (status & (UART_LSR_DR | UART_LSR_BI)) {
if (!up->dma || handle_rx_dma(up, iir))
status = serial8250_rx_chars(up, status);
}
serial8250_modem_status(up);
- if ((!up->dma || up->dma->tx_err) && (status & UART_LSR_THRE))
+ if ((!up->dma || up->dma->tx_err) && (status & UART_LSR_THRE) &&
+ (up->ier & UART_IER_THRI))
serial8250_tx_chars(up);
spin_unlock_irqrestore(&port->lock, flags);
diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
index e538959..ad40c75 100644
--- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c
@@ -407,7 +407,16 @@ static int cpm_uart_startup(struct uart_port *port)
clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_RX);
}
cpm_uart_initbd(pinfo);
- cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
+ if (IS_SMC(pinfo)) {
+ out_be32(&pinfo->smcup->smc_rstate, 0);
+ out_be32(&pinfo->smcup->smc_tstate, 0);
+ out_be16(&pinfo->smcup->smc_rbptr,
+ in_be16(&pinfo->smcup->smc_rbase));
+ out_be16(&pinfo->smcup->smc_tbptr,
+ in_be16(&pinfo->smcup->smc_tbase));
+ } else {
+ cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
+ }
}
/* Install interrupt handler. */
retval = request_irq(port->irq, cpm_uart_int, 0, "cpm_uart", port);
@@ -861,16 +870,14 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo)
(u8 __iomem *)pinfo->tx_bd_base - DPRAM_BASE);
/*
- * In case SMC1 is being relocated...
+ * In case SMC is being relocated...
*/
-#if defined (CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
out_be16(&up->smc_rbptr, in_be16(&pinfo->smcup->smc_rbase));
out_be16(&up->smc_tbptr, in_be16(&pinfo->smcup->smc_tbase));
out_be32(&up->smc_rstate, 0);
out_be32(&up->smc_tstate, 0);
out_be16(&up->smc_brkcr, 1); /* number of break chars */
out_be16(&up->smc_brkec, 0);
-#endif
/* Set up the uart parameters in the
* parameter ram.
@@ -884,8 +891,6 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo)
out_be16(&up->smc_brkec, 0);
out_be16(&up->smc_brkcr, 1);
- cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
-
/* Set UART mode, 8 bit, no parity, one stop.
* Enable receive and transmit.
*/
diff --git a/drivers/tty/serial/digicolor-usart.c b/drivers/tty/serial/digicolor-usart.c
index f460cca..13ac36e 100644
--- a/drivers/tty/serial/digicolor-usart.c
+++ b/drivers/tty/serial/digicolor-usart.c
@@ -541,7 +541,11 @@ static int __init digicolor_uart_init(void)
if (ret)
return ret;
- return platform_driver_register(&digicolor_uart_platform);
+ ret = platform_driver_register(&digicolor_uart_platform);
+ if (ret)
+ uart_unregister_driver(&digicolor_uart);
+
+ return ret;
}
module_init(digicolor_uart_init);
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 0f67197..105de92 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -382,6 +382,7 @@ static void imx_uart_ucrs_restore(struct imx_port *sport,
}
#endif
+/* called with port.lock taken and irqs caller dependent */
static void imx_uart_rts_active(struct imx_port *sport, u32 *ucr2)
{
*ucr2 &= ~(UCR2_CTSC | UCR2_CTS);
@@ -390,6 +391,7 @@ static void imx_uart_rts_active(struct imx_port *sport, u32 *ucr2)
mctrl_gpio_set(sport->gpios, sport->port.mctrl);
}
+/* called with port.lock taken and irqs caller dependent */
static void imx_uart_rts_inactive(struct imx_port *sport, u32 *ucr2)
{
*ucr2 &= ~UCR2_CTSC;
@@ -399,6 +401,7 @@ static void imx_uart_rts_inactive(struct imx_port *sport, u32 *ucr2)
mctrl_gpio_set(sport->gpios, sport->port.mctrl);
}
+/* called with port.lock taken and irqs caller dependent */
static void imx_uart_rts_auto(struct imx_port *sport, u32 *ucr2)
{
*ucr2 |= UCR2_CTSC;
@@ -1554,6 +1557,16 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
old_csize = CS8;
}
+ del_timer_sync(&sport->timer);
+
+ /*
+ * Ask the core to calculate the divisor for us.
+ */
+ baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16);
+ quot = uart_get_divisor(port, baud);
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+
if ((termios->c_cflag & CSIZE) == CS8)
ucr2 = UCR2_WS | UCR2_SRST | UCR2_IRTS;
else
@@ -1597,16 +1610,6 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
ucr2 |= UCR2_PROE;
}
- del_timer_sync(&sport->timer);
-
- /*
- * Ask the core to calculate the divisor for us.
- */
- baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16);
- quot = uart_get_divisor(port, baud);
-
- spin_lock_irqsave(&sport->port.lock, flags);
-
sport->port.read_status_mask = 0;
if (termios->c_iflag & INPCK)
sport->port.read_status_mask |= (URXD_FRMERR | URXD_PRERR);
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index 38c48a0..bd3e6cf 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -491,37 +491,48 @@ static bool max310x_reg_precious(struct device *dev, unsigned int reg)
static int max310x_set_baud(struct uart_port *port, int baud)
{
- unsigned int mode = 0, clk = port->uartclk, div = clk / baud;
+ unsigned int mode = 0, div = 0, frac = 0, c = 0, F = 0;
- /* Check for minimal value for divider */
- if (div < 16)
- div = 16;
-
- if (clk % baud && (div / 16) < 0x8000) {
+ /*
+ * Calculate the integer divisor first. Select a proper mode
+ * in case if the requested baud is too high for the pre-defined
+ * clocks frequency.
+ */
+ div = port->uartclk / baud;
+ if (div < 8) {
+ /* Mode x4 */
+ c = 4;
+ mode = MAX310X_BRGCFG_4XMODE_BIT;
+ } else if (div < 16) {
/* Mode x2 */
+ c = 8;
mode = MAX310X_BRGCFG_2XMODE_BIT;
- clk = port->uartclk * 2;
- div = clk / baud;
-
- if (clk % baud && (div / 16) < 0x8000) {
- /* Mode x4 */
- mode = MAX310X_BRGCFG_4XMODE_BIT;
- clk = port->uartclk * 4;
- div = clk / baud;
- }
+ } else {
+ c = 16;
}
- max310x_port_write(port, MAX310X_BRGDIVMSB_REG, (div / 16) >> 8);
- max310x_port_write(port, MAX310X_BRGDIVLSB_REG, div / 16);
- max310x_port_write(port, MAX310X_BRGCFG_REG, (div % 16) | mode);
+ /* Calculate the divisor in accordance with the fraction coefficient */
+ div /= c;
+ F = c*baud;
- return DIV_ROUND_CLOSEST(clk, div);
+ /* Calculate the baud rate fraction */
+ if (div > 0)
+ frac = (16*(port->uartclk % F)) / F;
+ else
+ div = 1;
+
+ max310x_port_write(port, MAX310X_BRGDIVMSB_REG, div >> 8);
+ max310x_port_write(port, MAX310X_BRGDIVLSB_REG, div);
+ max310x_port_write(port, MAX310X_BRGCFG_REG, frac | mode);
+
+ /* Return the actual baud rate we just programmed */
+ return (16*port->uartclk) / (c*(16*div + frac));
}
static int max310x_update_best_err(unsigned long f, long *besterr)
{
/* Use baudrate 115200 for calculate error */
- long err = f % (115200 * 16);
+ long err = f % (460800 * 16);
if ((*besterr < 0) || (*besterr > err)) {
*besterr = err;
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index 0f41b93..310bbae 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -383,10 +383,14 @@ static void msm_request_rx_dma(struct msm_port *msm_port, resource_size_t base)
static inline void msm_wait_for_xmitr(struct uart_port *port)
{
+ unsigned int timeout = 500000;
+
while (!(msm_read(port, UART_SR) & UART_SR_TX_EMPTY)) {
if (msm_read(port, UART_ISR) & UART_ISR_TX_READY)
break;
udelay(1);
+ if (!timeout--)
+ break;
}
msm_write(port, UART_CR_CMD_RESET_TX_READY, UART_CR);
}
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 8dbeb14..fe9261f 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -1738,6 +1738,7 @@ static int uart_port_activate(struct tty_port *port, struct tty_struct *tty)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport;
+ int ret;
uport = uart_port_check(state);
if (!uport || uport->flags & UPF_DEAD)
@@ -1748,7 +1749,11 @@ static int uart_port_activate(struct tty_port *port, struct tty_struct *tty)
/*
* Start up the serial port.
*/
- return uart_startup(tty, state, 0);
+ ret = uart_startup(tty, state, 0);
+ if (ret > 0)
+ tty_port_set_active(port, 1);
+
+ return ret;
}
static const char *uart_type(struct uart_port *port)
diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c
index 1c06325..07f3186 100644
--- a/drivers/tty/serial/serial_mctrl_gpio.c
+++ b/drivers/tty/serial/serial_mctrl_gpio.c
@@ -12,6 +12,7 @@
#include <linux/termios.h>
#include <linux/serial_core.h>
#include <linux/module.h>
+#include <linux/property.h>
#include "serial_mctrl_gpio.h"
@@ -115,6 +116,19 @@ struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx)
for (i = 0; i < UART_GPIO_MAX; i++) {
enum gpiod_flags flags;
+ char *gpio_str;
+ bool present;
+
+ /* Check if GPIO property exists and continue if not */
+ gpio_str = kasprintf(GFP_KERNEL, "%s-gpios",
+ mctrl_gpios_desc[i].name);
+ if (!gpio_str)
+ continue;
+
+ present = device_property_present(dev, gpio_str);
+ kfree(gpio_str);
+ if (!present)
+ continue;
if (mctrl_gpios_desc[i].dir_out)
flags = GPIOD_OUT_LOW;
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 040832635..5550289 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1376,6 +1376,7 @@ static void work_fn_tx(struct work_struct *work)
struct circ_buf *xmit = &port->state->xmit;
unsigned long flags;
dma_addr_t buf;
+ int head, tail;
/*
* DMA is idle now.
@@ -1385,16 +1386,23 @@ static void work_fn_tx(struct work_struct *work)
* consistent xmit buffer state.
*/
spin_lock_irq(&port->lock);
- buf = s->tx_dma_addr + (xmit->tail & (UART_XMIT_SIZE - 1));
+ head = xmit->head;
+ tail = xmit->tail;
+ buf = s->tx_dma_addr + (tail & (UART_XMIT_SIZE - 1));
s->tx_dma_len = min_t(unsigned int,
- CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE),
- CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE));
- spin_unlock_irq(&port->lock);
+ CIRC_CNT(head, tail, UART_XMIT_SIZE),
+ CIRC_CNT_TO_END(head, tail, UART_XMIT_SIZE));
+ if (!s->tx_dma_len) {
+ /* Transmit buffer has been flushed */
+ spin_unlock_irq(&port->lock);
+ return;
+ }
desc = dmaengine_prep_slave_single(chan, buf, s->tx_dma_len,
DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) {
+ spin_unlock_irq(&port->lock);
dev_warn(port->dev, "Failed preparing Tx DMA descriptor\n");
goto switch_to_pio;
}
@@ -1402,18 +1410,18 @@ static void work_fn_tx(struct work_struct *work)
dma_sync_single_for_device(chan->device->dev, buf, s->tx_dma_len,
DMA_TO_DEVICE);
- spin_lock_irq(&port->lock);
desc->callback = sci_dma_tx_complete;
desc->callback_param = s;
- spin_unlock_irq(&port->lock);
s->cookie_tx = dmaengine_submit(desc);
if (dma_submit_error(s->cookie_tx)) {
+ spin_unlock_irq(&port->lock);
dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n");
goto switch_to_pio;
}
+ spin_unlock_irq(&port->lock);
dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n",
- __func__, xmit->buf, xmit->tail, xmit->head, s->cookie_tx);
+ __func__, xmit->buf, tail, head, s->cookie_tx);
dma_async_issue_pending(chan);
return;
@@ -1633,11 +1641,18 @@ static void sci_free_dma(struct uart_port *port)
static void sci_flush_buffer(struct uart_port *port)
{
+ struct sci_port *s = to_sci_port(port);
+
/*
* In uart_flush_buffer(), the xmit circular buffer has just been
- * cleared, so we have to reset tx_dma_len accordingly.
+ * cleared, so we have to reset tx_dma_len accordingly, and stop any
+ * pending transfers
*/
- to_sci_port(port)->tx_dma_len = 0;
+ s->tx_dma_len = 0;
+ if (s->chan_tx) {
+ dmaengine_terminate_async(s->chan_tx);
+ s->cookie_tx = -EINVAL;
+ }
}
#else /* !CONFIG_SERIAL_SH_SCI_DMA */
static inline void sci_request_dma(struct uart_port *port)
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 27bed4a..4884591b 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -3589,6 +3589,7 @@ static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
struct usb_device *hdev;
struct usb_device *udev;
int connect_change = 0;
+ u16 link_state;
int ret;
hdev = hub->hdev;
@@ -3598,9 +3599,11 @@ static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
return 0;
usb_clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND);
} else {
+ link_state = portstatus & USB_PORT_STAT_LINK_STATE;
if (!udev || udev->state != USB_STATE_SUSPENDED ||
- (portstatus & USB_PORT_STAT_LINK_STATE) !=
- USB_SS_PORT_LS_U0)
+ (link_state != USB_SS_PORT_LS_U0 &&
+ link_state != USB_SS_PORT_LS_U1 &&
+ link_state != USB_SS_PORT_LS_U2))
return 0;
}
@@ -3972,6 +3975,9 @@ static int usb_set_lpm_timeout(struct usb_device *udev,
* control transfers to set the hub timeout or enable device-initiated U1/U2
* will be successful.
*
+ * If the control transfer to enable device-initiated U1/U2 entry fails, then
+ * hub-initiated U1/U2 will be disabled.
+ *
* If we cannot set the parent hub U1/U2 timeout, we attempt to let the xHCI
* driver know about it. If that call fails, it should be harmless, and just
* take up more slightly more bus bandwidth for unnecessary U1/U2 exit latency.
@@ -4026,23 +4032,24 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
* host know that this link state won't be enabled.
*/
hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state);
- } else {
- /* Only a configured device will accept the Set Feature
- * U1/U2_ENABLE
- */
- if (udev->actconfig)
- usb_set_device_initiated_lpm(udev, state, true);
+ return;
+ }
- /* As soon as usb_set_lpm_timeout(timeout) returns 0, the
- * hub-initiated LPM is enabled. Thus, LPM is enabled no
- * matter the result of usb_set_device_initiated_lpm().
- * The only difference is whether device is able to initiate
- * LPM.
- */
+ /* Only a configured device will accept the Set Feature
+ * U1/U2_ENABLE
+ */
+ if (udev->actconfig &&
+ usb_set_device_initiated_lpm(udev, state, true) == 0) {
if (state == USB3_LPM_U1)
udev->usb3_lpm_u1_enabled = 1;
else if (state == USB3_LPM_U2)
udev->usb3_lpm_u2_enabled = 1;
+ } else {
+ /* Don't request U1/U2 entry if the device
+ * cannot transition to U1/U2.
+ */
+ usb_set_lpm_timeout(udev, state, 0);
+ hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state);
}
}
diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
index 55d5ae2..51d83f7 100644
--- a/drivers/usb/dwc2/core.c
+++ b/drivers/usb/dwc2/core.c
@@ -531,7 +531,7 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
}
/* Wait for AHB master IDLE state */
- if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 50)) {
+ if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL, GRSTCTL_AHBIDLE, 10000)) {
dev_warn(hsotg->dev, "%s: HANG! AHB Idle timeout GRSTCTL GRSTCTL_AHBIDLE\n",
__func__);
return -EBUSY;
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 03614ef..3f68edd 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -3125,6 +3125,7 @@ void dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg)
hsotg->connected = 0;
hsotg->test_mode = 0;
+ /* all endpoints should be shutdown */
for (ep = 0; ep < hsotg->num_of_eps; ep++) {
if (hsotg->eps_in[ep])
kill_all_requests(hsotg, hsotg->eps_in[ep],
@@ -3175,6 +3176,7 @@ static void dwc2_hsotg_irq_fifoempty(struct dwc2_hsotg *hsotg, bool periodic)
GINTSTS_PTXFEMP | \
GINTSTS_RXFLVL)
+static int dwc2_hsotg_ep_disable(struct usb_ep *ep);
/**
* dwc2_hsotg_core_init - issue softreset to the core
* @hsotg: The device state
@@ -3189,13 +3191,23 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
u32 val;
u32 usbcfg;
u32 dcfg = 0;
+ int ep;
/* Kill any ep0 requests as controller will be reinitialized */
kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET);
- if (!is_usb_reset)
+ if (!is_usb_reset) {
if (dwc2_core_reset(hsotg, true))
return;
+ } else {
+ /* all endpoints should be shutdown */
+ for (ep = 1; ep < hsotg->num_of_eps; ep++) {
+ if (hsotg->eps_in[ep])
+ dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep);
+ if (hsotg->eps_out[ep])
+ dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep);
+ }
+ }
/*
* we must now enable ep0 ready for host detection and then
@@ -3993,7 +4005,6 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep)
struct dwc2_hsotg *hsotg = hs_ep->parent;
int dir_in = hs_ep->dir_in;
int index = hs_ep->index;
- unsigned long flags;
u32 epctrl_reg;
u32 ctrl;
@@ -4011,8 +4022,6 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep)
epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
- spin_lock_irqsave(&hsotg->lock, flags);
-
ctrl = dwc2_readl(hsotg, epctrl_reg);
if (ctrl & DXEPCTL_EPENA)
@@ -4035,10 +4044,22 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep)
hs_ep->fifo_index = 0;
hs_ep->fifo_size = 0;
- spin_unlock_irqrestore(&hsotg->lock, flags);
return 0;
}
+static int dwc2_hsotg_ep_disable_lock(struct usb_ep *ep)
+{
+ struct dwc2_hsotg_ep *hs_ep = our_ep(ep);
+ struct dwc2_hsotg *hsotg = hs_ep->parent;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&hsotg->lock, flags);
+ ret = dwc2_hsotg_ep_disable(ep);
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+ return ret;
+}
+
/**
* on_list - check request is on the given endpoint
* @ep: The endpoint to check.
@@ -4186,7 +4207,7 @@ static int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value)
static const struct usb_ep_ops dwc2_hsotg_ep_ops = {
.enable = dwc2_hsotg_ep_enable,
- .disable = dwc2_hsotg_ep_disable,
+ .disable = dwc2_hsotg_ep_disable_lock,
.alloc_request = dwc2_hsotg_ep_alloc_request,
.free_request = dwc2_hsotg_ep_free_request,
.queue = dwc2_hsotg_ep_queue_lock,
@@ -4326,9 +4347,9 @@ static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget)
/* all endpoints should be shutdown */
for (ep = 1; ep < hsotg->num_of_eps; ep++) {
if (hsotg->eps_in[ep])
- dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep);
+ dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep);
if (hsotg->eps_out[ep])
- dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep);
+ dwc2_hsotg_ep_disable_lock(&hsotg->eps_out[ep]->ep);
}
spin_lock_irqsave(&hsotg->lock, flags);
@@ -4776,9 +4797,9 @@ int dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg)
for (ep = 0; ep < hsotg->num_of_eps; ep++) {
if (hsotg->eps_in[ep])
- dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep);
+ dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep);
if (hsotg->eps_out[ep])
- dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep);
+ dwc2_hsotg_ep_disable_lock(&hsotg->eps_out[ep]->ep);
}
}
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index b2b24e1..413a44e 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1260,7 +1260,14 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
unsigned int rem = length % maxp;
unsigned chain = true;
- if (sg_is_last(s))
+ /*
+ * IOMMU driver is clubbing the list of sgs which shares a page
+ * boundary into one and giving it to USB driver. With this the
+ * number of sgs mapped it not equal to the the number of sgs
+ * passed. Mark the chain bit to false if it is the last mapped
+ * sg.
+ */
+ if (sg_is_last(s) || (i == remaining - 1))
chain = false;
if (rem && usb_endpoint_dir_out(dep->endpoint.desc) && !chain) {
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index f294228..f916f87 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -1202,11 +1202,12 @@ static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from)
ffs_log("enter");
if (!is_sync_kiocb(kiocb)) {
- p = kmalloc(sizeof(io_data), GFP_KERNEL);
+ p = kzalloc(sizeof(io_data), GFP_KERNEL);
if (unlikely(!p))
return -ENOMEM;
p->aio = true;
} else {
+ memset(p, 0, sizeof(*p));
p->aio = false;
}
@@ -1245,11 +1246,12 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to)
ffs_log("enter");
if (!is_sync_kiocb(kiocb)) {
- p = kmalloc(sizeof(io_data), GFP_KERNEL);
+ p = kzalloc(sizeof(io_data), GFP_KERNEL);
if (unlikely(!p))
return -ENOMEM;
p->aio = true;
} else {
+ memset(p, 0, sizeof(*p));
p->aio = false;
}
@@ -1363,6 +1365,7 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code,
struct usb_endpoint_descriptor desc1, *desc;
switch (epfile->ffs->gadget->speed) {
+ case USB_SPEED_SUPER_PLUS:
case USB_SPEED_SUPER:
desc_idx = 2;
break;
diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c
index cf3dc1d..cdb6d62 100644
--- a/drivers/usb/gadget/function/f_gsi.c
+++ b/drivers/usb/gadget/function/f_gsi.c
@@ -1439,9 +1439,9 @@ static long gsi_ctrl_dev_ioctl(struct file *fp, unsigned int cmd,
gsi = inst_cur->opts->gsi;
c_port = &gsi->c_port;
- if (!c_port) {
- log_event_err("%s: gsi ctrl port %pK", __func__, c_port);
- return -ENODEV;
+ if (!atomic_read(&gsi->connected)) {
+ log_event_err("USB cable not connected\n");
+ return -ECONNRESET;
}
switch (cmd) {
@@ -1807,7 +1807,7 @@ static int gsi_ctrl_send_notification(struct f_gsi *gsi)
__le32 *data;
struct usb_cdc_notification *event;
struct usb_request *req = gsi->c_port.notify_req;
- struct usb_composite_dev *cdev = gsi->function.config->cdev;
+ struct usb_composite_dev *cdev;
struct gsi_ctrl_pkt *cpkt;
unsigned long flags;
bool del_free_cpkt = false;
@@ -1838,6 +1838,7 @@ static int gsi_ctrl_send_notification(struct f_gsi *gsi)
log_event_dbg("%s: cpkt->type:%d\n", __func__, cpkt->type);
event = req->buf;
+ cdev = gsi->function.config->cdev;
switch (cpkt->type) {
case GSI_CTRL_NOTIFY_CONNECT:
diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c
index 0b64fbe..1212e7e 100644
--- a/drivers/usb/gadget/function/f_qdss.c
+++ b/drivers/usb/gadget/function/f_qdss.c
@@ -915,6 +915,9 @@ int usb_qdss_write(struct usb_qdss_ch *ch, struct qdss_request *d_req)
req->buf = d_req->buf;
req->length = d_req->length;
req->context = d_req;
+ req->sg = d_req->sg;
+ req->num_sgs = d_req->num_sgs;
+ req->num_mapped_sgs = d_req->num_mapped_sgs;
if (usb_ep_queue(qdss->port.data, req, GFP_ATOMIC)) {
spin_lock_irqsave(&qdss->lock, flags);
list_add_tail(&req->list, &qdss->data_write_pool);
diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index c7a5c08..ff0ce60 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -187,11 +187,12 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
out = dev->port_usb->out_ep;
else
out = NULL;
- spin_unlock_irqrestore(&dev->lock, flags);
if (!out)
+ {
+ spin_unlock_irqrestore(&dev->lock, flags);
return -ENOTCONN;
-
+ }
/* Padding up to RX_EXTRA handles minor disagreements with host.
* Normally we use the USB "terminate on short read" convention;
@@ -218,6 +219,7 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
if (dev->port_usb->is_fixed)
size = max_t(size_t, size, dev->port_usb->fixed_out_len);
+ spin_unlock_irqrestore(&dev->lock, flags);
DBG(dev, "%s: size: %zd\n", __func__, size);
skb = __netdev_alloc_skb(dev->net, size + NET_IP_ALIGN, gfp_flags);
diff --git a/drivers/usb/host/hwa-hc.c b/drivers/usb/host/hwa-hc.c
index 09a8ebd..6968b9f 100644
--- a/drivers/usb/host/hwa-hc.c
+++ b/drivers/usb/host/hwa-hc.c
@@ -159,7 +159,7 @@ static int hwahc_op_start(struct usb_hcd *usb_hcd)
return result;
error_set_cluster_id:
- wusb_cluster_id_put(wusbhc->cluster_id);
+ wusb_cluster_id_put(addr);
error_cluster_id_get:
goto out;
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 3625a5c..070c66f 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -205,7 +205,7 @@ int usb_amd_find_chipset_info(void)
{
unsigned long flags;
struct amd_chipset_info info;
- int ret;
+ int need_pll_quirk = 0;
spin_lock_irqsave(&amd_lock, flags);
@@ -219,21 +219,28 @@ int usb_amd_find_chipset_info(void)
spin_unlock_irqrestore(&amd_lock, flags);
if (!amd_chipset_sb_type_init(&info)) {
- ret = 0;
goto commit;
}
- /* Below chipset generations needn't enable AMD PLL quirk */
- if (info.sb_type.gen == AMD_CHIPSET_UNKNOWN ||
- info.sb_type.gen == AMD_CHIPSET_SB600 ||
- info.sb_type.gen == AMD_CHIPSET_YANGTZE ||
- (info.sb_type.gen == AMD_CHIPSET_SB700 &&
- info.sb_type.rev > 0x3b)) {
+ switch (info.sb_type.gen) {
+ case AMD_CHIPSET_SB700:
+ need_pll_quirk = info.sb_type.rev <= 0x3B;
+ break;
+ case AMD_CHIPSET_SB800:
+ case AMD_CHIPSET_HUDSON2:
+ case AMD_CHIPSET_BOLTON:
+ need_pll_quirk = 1;
+ break;
+ default:
+ need_pll_quirk = 0;
+ break;
+ }
+
+ if (!need_pll_quirk) {
if (info.smbus_dev) {
pci_dev_put(info.smbus_dev);
info.smbus_dev = NULL;
}
- ret = 0;
goto commit;
}
@@ -252,7 +259,7 @@ int usb_amd_find_chipset_info(void)
}
}
- ret = info.probe_result = 1;
+ need_pll_quirk = info.probe_result = 1;
printk(KERN_DEBUG "QUIRK: Enable AMD PLL fix\n");
commit:
@@ -263,7 +270,7 @@ int usb_amd_find_chipset_info(void)
/* Mark that we where here */
amd_chipset.probe_count++;
- ret = amd_chipset.probe_result;
+ need_pll_quirk = amd_chipset.probe_result;
spin_unlock_irqrestore(&amd_lock, flags);
@@ -277,7 +284,7 @@ int usb_amd_find_chipset_info(void)
spin_unlock_irqrestore(&amd_lock, flags);
}
- return ret;
+ return need_pll_quirk;
}
EXPORT_SYMBOL_GPL(usb_amd_find_chipset_info);
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
index 39fa2fc..6036cba 100644
--- a/drivers/usb/renesas_usbhs/fifo.c
+++ b/drivers/usb/renesas_usbhs/fifo.c
@@ -802,9 +802,8 @@ static int __usbhsf_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
}
static void usbhsf_dma_complete(void *arg);
-static void xfer_work(struct work_struct *work)
+static void usbhsf_dma_xfer_preparing(struct usbhs_pkt *pkt)
{
- struct usbhs_pkt *pkt = container_of(work, struct usbhs_pkt, work);
struct usbhs_pipe *pipe = pkt->pipe;
struct usbhs_fifo *fifo;
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
@@ -812,12 +811,10 @@ static void xfer_work(struct work_struct *work)
struct dma_chan *chan;
struct device *dev = usbhs_priv_to_dev(priv);
enum dma_transfer_direction dir;
- unsigned long flags;
- usbhs_lock(priv, flags);
fifo = usbhs_pipe_to_fifo(pipe);
if (!fifo)
- goto xfer_work_end;
+ return;
chan = usbhsf_dma_chan_get(fifo, pkt);
dir = usbhs_pipe_is_dir_in(pipe) ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
@@ -826,7 +823,7 @@ static void xfer_work(struct work_struct *work)
pkt->trans, dir,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc)
- goto xfer_work_end;
+ return;
desc->callback = usbhsf_dma_complete;
desc->callback_param = pipe;
@@ -834,7 +831,7 @@ static void xfer_work(struct work_struct *work)
pkt->cookie = dmaengine_submit(desc);
if (pkt->cookie < 0) {
dev_err(dev, "Failed to submit dma descriptor\n");
- goto xfer_work_end;
+ return;
}
dev_dbg(dev, " %s %d (%d/ %d)\n",
@@ -845,8 +842,17 @@ static void xfer_work(struct work_struct *work)
dma_async_issue_pending(chan);
usbhsf_dma_start(pipe, fifo);
usbhs_pipe_enable(pipe);
+}
-xfer_work_end:
+static void xfer_work(struct work_struct *work)
+{
+ struct usbhs_pkt *pkt = container_of(work, struct usbhs_pkt, work);
+ struct usbhs_pipe *pipe = pkt->pipe;
+ struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
+ unsigned long flags;
+
+ usbhs_lock(priv, flags);
+ usbhsf_dma_xfer_preparing(pkt);
usbhs_unlock(priv, flags);
}
@@ -899,8 +905,13 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done)
pkt->trans = len;
usbhsf_tx_irq_ctrl(pipe, 0);
- INIT_WORK(&pkt->work, xfer_work);
- schedule_work(&pkt->work);
+ /* FIXME: Workaound for usb dmac that driver can be used in atomic */
+ if (usbhs_get_dparam(priv, has_usb_dmac)) {
+ usbhsf_dma_xfer_preparing(pkt);
+ } else {
+ INIT_WORK(&pkt->work, xfer_work);
+ schedule_work(&pkt->work);
+ }
return 0;
@@ -1006,8 +1017,7 @@ static int usbhsf_dma_prepare_pop_with_usb_dmac(struct usbhs_pkt *pkt,
pkt->trans = pkt->length;
- INIT_WORK(&pkt->work, xfer_work);
- schedule_work(&pkt->work);
+ usbhsf_dma_xfer_preparing(pkt);
return 0;
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index c0dc4bc..e18735e 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -1019,6 +1019,7 @@ static const struct usb_device_id id_table_combined[] = {
{ USB_DEVICE(AIRBUS_DS_VID, AIRBUS_DS_P8GR) },
/* EZPrototypes devices */
{ USB_DEVICE(EZPROTOTYPES_VID, HJELMSLUND_USB485_ISO_PID) },
+ { USB_DEVICE_INTERFACE_NUMBER(UNJO_VID, UNJO_ISODEBUG_V1_PID, 1) },
{ } /* Terminating entry */
};
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index 5755f0d..f12d806 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -1543,3 +1543,9 @@
#define CHETCO_SEASMART_DISPLAY_PID 0xA5AD /* SeaSmart NMEA2000 Display */
#define CHETCO_SEASMART_LITE_PID 0xA5AE /* SeaSmart Lite USB Adapter */
#define CHETCO_SEASMART_ANALOG_PID 0xA5AF /* SeaSmart Analog Adapter */
+
+/*
+ * Unjo AB
+ */
+#define UNJO_VID 0x22B7
+#define UNJO_ISODEBUG_V1_PID 0x150D
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index ea89119..e0a4749 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -1343,6 +1343,7 @@ static const struct usb_device_id option_ids[] = {
.driver_info = RSVD(4) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0414, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0417, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_INTERFACE_CLASS(ZTE_VENDOR_ID, 0x0601, 0xff) }, /* GosunCn ZTE WeLink ME3630 (RNDIS mode) */
{ USB_DEVICE_INTERFACE_CLASS(ZTE_VENDOR_ID, 0x0602, 0xff) }, /* GosunCn ZTE WeLink ME3630 (MBIM mode) */
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff),
.driver_info = RSVD(4) },
diff --git a/drivers/usb/typec/tps6598x.c b/drivers/usb/typec/tps6598x.c
index eb8046f..987b8fcf 100644
--- a/drivers/usb/typec/tps6598x.c
+++ b/drivers/usb/typec/tps6598x.c
@@ -39,7 +39,7 @@
#define TPS_STATUS_VCONN(s) (!!((s) & BIT(7)))
/* TPS_REG_SYSTEM_CONF bits */
-#define TPS_SYSCONF_PORTINFO(c) ((c) & 3)
+#define TPS_SYSCONF_PORTINFO(c) ((c) & 7)
enum {
TPS_PORTINFO_SINK,
@@ -111,7 +111,7 @@ tps6598x_block_read(struct tps6598x *tps, u8 reg, void *val, size_t len)
}
static int tps6598x_block_write(struct tps6598x *tps, u8 reg,
- void *val, size_t len)
+ const void *val, size_t len)
{
u8 data[TPS_MAX_LEN + 1];
@@ -157,7 +157,7 @@ static inline int tps6598x_write64(struct tps6598x *tps, u8 reg, u64 val)
static inline int
tps6598x_write_4cc(struct tps6598x *tps, u8 reg, const char *val)
{
- return tps6598x_block_write(tps, reg, &val, sizeof(u32));
+ return tps6598x_block_write(tps, reg, val, 4);
}
static int tps6598x_read_partner_identity(struct tps6598x *tps)
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 39155d7..124356d 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -36,7 +36,7 @@
#include "vhost.h"
-static int experimental_zcopytx = 1;
+static int experimental_zcopytx = 0;
module_param(experimental_zcopytx, int, 0444);
MODULE_PARM_DESC(experimental_zcopytx, "Enable Zero Copy TX;"
" 1 -Enable; 0 - Disable");
@@ -497,12 +497,6 @@ static size_t init_iov_iter(struct vhost_virtqueue *vq, struct iov_iter *iter,
return iov_iter_count(iter);
}
-static bool vhost_exceeds_weight(int pkts, int total_len)
-{
- return total_len >= VHOST_NET_WEIGHT ||
- pkts >= VHOST_NET_PKT_WEIGHT;
-}
-
static int get_tx_bufs(struct vhost_net *net,
struct vhost_net_virtqueue *nvq,
struct msghdr *msg,
@@ -557,7 +551,7 @@ static void handle_tx_copy(struct vhost_net *net, struct socket *sock)
int err;
int sent_pkts = 0;
- for (;;) {
+ do {
bool busyloop_intr = false;
head = get_tx_bufs(net, nvq, &msg, &out, &in, &len,
@@ -598,11 +592,7 @@ static void handle_tx_copy(struct vhost_net *net, struct socket *sock)
err, len);
if (++nvq->done_idx >= VHOST_NET_BATCH)
vhost_net_signal_used(nvq);
- if (vhost_exceeds_weight(++sent_pkts, total_len)) {
- vhost_poll_queue(&vq->poll);
- break;
- }
- }
+ } while (likely(!vhost_exceeds_weight(vq, ++sent_pkts, total_len)));
vhost_net_signal_used(nvq);
}
@@ -626,7 +616,7 @@ static void handle_tx_zerocopy(struct vhost_net *net, struct socket *sock)
bool zcopy_used;
int sent_pkts = 0;
- for (;;) {
+ do {
bool busyloop_intr;
/* Release DMAs done buffers first */
@@ -701,11 +691,7 @@ static void handle_tx_zerocopy(struct vhost_net *net, struct socket *sock)
else
vhost_zerocopy_signal_used(net, vq);
vhost_net_tx_packet(net);
- if (unlikely(vhost_exceeds_weight(++sent_pkts, total_len))) {
- vhost_poll_queue(&vq->poll);
- break;
- }
- }
+ } while (likely(!vhost_exceeds_weight(vq, ++sent_pkts, total_len)));
}
/* Expects to be always run from workqueue - which acts as
@@ -941,8 +927,11 @@ static void handle_rx(struct vhost_net *net)
vq->log : NULL;
mergeable = vhost_has_feature(vq, VIRTIO_NET_F_MRG_RXBUF);
- while ((sock_len = vhost_net_rx_peek_head_len(net, sock->sk,
- &busyloop_intr))) {
+ do {
+ sock_len = vhost_net_rx_peek_head_len(net, sock->sk,
+ &busyloop_intr);
+ if (!sock_len)
+ break;
sock_len += sock_hlen;
vhost_len = sock_len + vhost_hlen;
headcount = get_rx_bufs(vq, vq->heads + nvq->done_idx,
@@ -1027,14 +1016,11 @@ static void handle_rx(struct vhost_net *net)
vhost_log_write(vq, vq_log, log, vhost_len,
vq->iov, in);
total_len += vhost_len;
- if (unlikely(vhost_exceeds_weight(++recv_pkts, total_len))) {
- vhost_poll_queue(&vq->poll);
- goto out;
- }
- }
+ } while (likely(!vhost_exceeds_weight(vq, ++recv_pkts, total_len)));
+
if (unlikely(busyloop_intr))
vhost_poll_queue(&vq->poll);
- else
+ else if (!sock_len)
vhost_net_enable_vq(net, vq);
out:
vhost_net_signal_used(nvq);
@@ -1115,7 +1101,8 @@ static int vhost_net_open(struct inode *inode, struct file *f)
vhost_net_buf_init(&n->vqs[i].rxq);
}
vhost_dev_init(dev, vqs, VHOST_NET_VQ_MAX,
- UIO_MAXIOV + VHOST_NET_BATCH);
+ UIO_MAXIOV + VHOST_NET_BATCH,
+ VHOST_NET_PKT_WEIGHT, VHOST_NET_WEIGHT);
vhost_poll_init(n->poll + VHOST_NET_VQ_TX, handle_tx_net, EPOLLOUT, dev);
vhost_poll_init(n->poll + VHOST_NET_VQ_RX, handle_rx_net, EPOLLIN, dev);
diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
index 0cfa925..5e298d9 100644
--- a/drivers/vhost/scsi.c
+++ b/drivers/vhost/scsi.c
@@ -57,6 +57,12 @@
#define VHOST_SCSI_PREALLOC_UPAGES 2048
#define VHOST_SCSI_PREALLOC_PROT_SGLS 2048
+/* Max number of requests before requeueing the job.
+ * Using this limit prevents one virtqueue from starving others with
+ * request.
+ */
+#define VHOST_SCSI_WEIGHT 256
+
struct vhost_scsi_inflight {
/* Wait for the flush operation to finish */
struct completion comp;
@@ -811,7 +817,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
u64 tag;
u32 exp_data_len, data_direction;
unsigned int out = 0, in = 0;
- int head, ret, prot_bytes;
+ int head, ret, prot_bytes, c = 0;
size_t req_size, rsp_size = sizeof(struct virtio_scsi_cmd_resp);
size_t out_size, in_size;
u16 lun;
@@ -830,7 +836,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
vhost_disable_notify(&vs->dev, vq);
- for (;;) {
+ do {
head = vhost_get_vq_desc(vq, vq->iov,
ARRAY_SIZE(vq->iov), &out, &in,
NULL, NULL);
@@ -1045,7 +1051,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
*/
INIT_WORK(&cmd->work, vhost_scsi_submission_work);
queue_work(vhost_scsi_workqueue, &cmd->work);
- }
+ } while (likely(!vhost_exceeds_weight(vq, ++c, 0)));
out:
mutex_unlock(&vq->mutex);
}
@@ -1398,7 +1404,8 @@ static int vhost_scsi_open(struct inode *inode, struct file *f)
vqs[i] = &vs->vqs[i].vq;
vs->vqs[i].vq.handle_kick = vhost_scsi_handle_kick;
}
- vhost_dev_init(&vs->dev, vqs, VHOST_SCSI_MAX_VQ, UIO_MAXIOV);
+ vhost_dev_init(&vs->dev, vqs, VHOST_SCSI_MAX_VQ, UIO_MAXIOV,
+ VHOST_SCSI_WEIGHT, 0);
vhost_scsi_init_inflight(vs, NULL);
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index c163bc1..0752f8d 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -413,8 +413,24 @@ static void vhost_dev_free_iovecs(struct vhost_dev *dev)
vhost_vq_free_iovecs(dev->vqs[i]);
}
+bool vhost_exceeds_weight(struct vhost_virtqueue *vq,
+ int pkts, int total_len)
+{
+ struct vhost_dev *dev = vq->dev;
+
+ if ((dev->byte_weight && total_len >= dev->byte_weight) ||
+ pkts >= dev->weight) {
+ vhost_poll_queue(&vq->poll);
+ return true;
+ }
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(vhost_exceeds_weight);
+
void vhost_dev_init(struct vhost_dev *dev,
- struct vhost_virtqueue **vqs, int nvqs, int iov_limit)
+ struct vhost_virtqueue **vqs, int nvqs,
+ int iov_limit, int weight, int byte_weight)
{
struct vhost_virtqueue *vq;
int i;
@@ -428,6 +444,8 @@ void vhost_dev_init(struct vhost_dev *dev,
dev->mm = NULL;
dev->worker = NULL;
dev->iov_limit = iov_limit;
+ dev->weight = weight;
+ dev->byte_weight = byte_weight;
init_llist_head(&dev->work_list);
init_waitqueue_head(&dev->wait);
INIT_LIST_HEAD(&dev->read_list);
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
index 9490e7d..27a78a9 100644
--- a/drivers/vhost/vhost.h
+++ b/drivers/vhost/vhost.h
@@ -171,10 +171,13 @@ struct vhost_dev {
struct list_head pending_list;
wait_queue_head_t wait;
int iov_limit;
+ int weight;
+ int byte_weight;
};
+bool vhost_exceeds_weight(struct vhost_virtqueue *vq, int pkts, int total_len);
void vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue **vqs,
- int nvqs, int iov_limit);
+ int nvqs, int iov_limit, int weight, int byte_weight);
long vhost_dev_set_owner(struct vhost_dev *dev);
bool vhost_dev_has_owner(struct vhost_dev *dev);
long vhost_dev_check_owner(struct vhost_dev *);
diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c
index e440f87..bab495d 100644
--- a/drivers/vhost/vsock.c
+++ b/drivers/vhost/vsock.c
@@ -21,6 +21,14 @@
#include "vhost.h"
#define VHOST_VSOCK_DEFAULT_HOST_CID 2
+/* Max number of bytes transferred before requeueing the job.
+ * Using this limit prevents one virtqueue from starving others. */
+#define VHOST_VSOCK_WEIGHT 0x80000
+/* Max number of packets transferred before requeueing the job.
+ * Using this limit prevents one virtqueue from starving others with
+ * small pkts.
+ */
+#define VHOST_VSOCK_PKT_WEIGHT 256
enum {
VHOST_VSOCK_FEATURES = VHOST_FEATURES,
@@ -78,6 +86,7 @@ vhost_transport_do_send_pkt(struct vhost_vsock *vsock,
struct vhost_virtqueue *vq)
{
struct vhost_virtqueue *tx_vq = &vsock->vqs[VSOCK_VQ_TX];
+ int pkts = 0, total_len = 0;
bool added = false;
bool restart_tx = false;
@@ -89,7 +98,7 @@ vhost_transport_do_send_pkt(struct vhost_vsock *vsock,
/* Avoid further vmexits, we're already processing the virtqueue */
vhost_disable_notify(&vsock->dev, vq);
- for (;;) {
+ do {
struct virtio_vsock_pkt *pkt;
struct iov_iter iov_iter;
unsigned out, in;
@@ -174,8 +183,9 @@ vhost_transport_do_send_pkt(struct vhost_vsock *vsock,
*/
virtio_transport_deliver_tap_pkt(pkt);
+ total_len += pkt->len;
virtio_transport_free_pkt(pkt);
- }
+ } while(likely(!vhost_exceeds_weight(vq, ++pkts, total_len)));
if (added)
vhost_signal(&vsock->dev, vq);
@@ -350,7 +360,7 @@ static void vhost_vsock_handle_tx_kick(struct vhost_work *work)
struct vhost_vsock *vsock = container_of(vq->dev, struct vhost_vsock,
dev);
struct virtio_vsock_pkt *pkt;
- int head;
+ int head, pkts = 0, total_len = 0;
unsigned int out, in;
bool added = false;
@@ -360,7 +370,7 @@ static void vhost_vsock_handle_tx_kick(struct vhost_work *work)
goto out;
vhost_disable_notify(&vsock->dev, vq);
- for (;;) {
+ do {
u32 len;
if (!vhost_vsock_more_replies(vsock)) {
@@ -401,9 +411,11 @@ static void vhost_vsock_handle_tx_kick(struct vhost_work *work)
else
virtio_transport_free_pkt(pkt);
- vhost_add_used(vq, head, sizeof(pkt->hdr) + len);
+ len += sizeof(pkt->hdr);
+ vhost_add_used(vq, head, len);
+ total_len += len;
added = true;
- }
+ } while(likely(!vhost_exceeds_weight(vq, ++pkts, total_len)));
no_more_replies:
if (added)
@@ -531,7 +543,9 @@ static int vhost_vsock_dev_open(struct inode *inode, struct file *file)
vsock->vqs[VSOCK_VQ_TX].handle_kick = vhost_vsock_handle_tx_kick;
vsock->vqs[VSOCK_VQ_RX].handle_kick = vhost_vsock_handle_rx_kick;
- vhost_dev_init(&vsock->dev, vqs, ARRAY_SIZE(vsock->vqs), UIO_MAXIOV);
+ vhost_dev_init(&vsock->dev, vqs, ARRAY_SIZE(vsock->vqs),
+ UIO_MAXIOV, VHOST_VSOCK_PKT_WEIGHT,
+ VHOST_VSOCK_WEIGHT);
file->private_data = vsock;
spin_lock_init(&vsock->send_pkt_list_lock);
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index 7ab6cae..d4e8b717 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -527,8 +527,15 @@ static void balloon_process(struct work_struct *work)
state = reserve_additional_memory();
}
- if (credit < 0)
- state = decrease_reservation(-credit, GFP_BALLOON);
+ if (credit < 0) {
+ long n_pages;
+
+ n_pages = min(-credit, si_mem_available());
+ state = decrease_reservation(n_pages, GFP_BALLOON);
+ if (state == BP_DONE && n_pages != -credit &&
+ n_pages < totalreserve_pages)
+ state = BP_EAGAIN;
+ }
state = update_schedule(state);
@@ -567,6 +574,9 @@ static int add_ballooned_pages(int nr_pages)
}
}
+ if (si_mem_available() < nr_pages)
+ return -ENOMEM;
+
st = decrease_reservation(nr_pages, GFP_USER);
if (st != BP_DONE)
return -ENOMEM;
@@ -696,7 +706,7 @@ static int __init balloon_init(void)
balloon_stats.schedule_delay = 1;
balloon_stats.max_schedule_delay = 32;
balloon_stats.retry_count = 1;
- balloon_stats.max_retry_count = RETRY_UNLIMITED;
+ balloon_stats.max_retry_count = 4;
#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
set_online_page_callback(&xen_online_page);
diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c
index fe1f163..8d49b91 100644
--- a/drivers/xen/events/events_base.c
+++ b/drivers/xen/events/events_base.c
@@ -1293,7 +1293,7 @@ void rebind_evtchn_irq(int evtchn, int irq)
}
/* Rebind an evtchn so that it gets delivered to a specific cpu */
-int xen_rebind_evtchn_to_cpu(int evtchn, unsigned tcpu)
+static int xen_rebind_evtchn_to_cpu(int evtchn, unsigned int tcpu)
{
struct evtchn_bind_vcpu bind_vcpu;
int masked;
@@ -1327,7 +1327,6 @@ int xen_rebind_evtchn_to_cpu(int evtchn, unsigned tcpu)
return 0;
}
-EXPORT_SYMBOL_GPL(xen_rebind_evtchn_to_cpu);
static int set_affinity_irq(struct irq_data *data, const struct cpumask *dest,
bool force)
@@ -1341,6 +1340,15 @@ static int set_affinity_irq(struct irq_data *data, const struct cpumask *dest,
return ret;
}
+/* To be called with desc->lock held. */
+int xen_set_affinity_evtchn(struct irq_desc *desc, unsigned int tcpu)
+{
+ struct irq_data *d = irq_desc_get_irq_data(desc);
+
+ return set_affinity_irq(d, cpumask_of(tcpu), false);
+}
+EXPORT_SYMBOL_GPL(xen_set_affinity_evtchn);
+
static void enable_dynirq(struct irq_data *data)
{
int evtchn = evtchn_from_irq(data->irq);
diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c
index 6d1a5e5..47c70b8 100644
--- a/drivers/xen/evtchn.c
+++ b/drivers/xen/evtchn.c
@@ -447,7 +447,7 @@ static void evtchn_bind_interdom_next_vcpu(int evtchn)
this_cpu_write(bind_last_selected_cpu, selected_cpu);
/* unmask expects irqs to be disabled */
- xen_rebind_evtchn_to_cpu(evtchn, selected_cpu);
+ xen_set_affinity_evtchn(desc, selected_cpu);
raw_spin_unlock_irqrestore(&desc->lock, flags);
}
diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c
index aa081f8..3d99975 100644
--- a/drivers/xen/swiotlb-xen.c
+++ b/drivers/xen/swiotlb-xen.c
@@ -357,8 +357,8 @@ xen_swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
/* Convert the size to actually allocated. */
size = 1UL << (order + XEN_PAGE_SHIFT);
- if (((dev_addr + size - 1 <= dma_mask)) ||
- range_straddles_page_boundary(phys, size))
+ if (!WARN_ON((dev_addr + size - 1 > dma_mask) ||
+ range_straddles_page_boundary(phys, size)))
xen_destroy_contiguous_region(phys, order);
xen_free_coherent_pages(hwdev, size, vaddr, (dma_addr_t)phys, attrs);
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 7e099a7..4dc15b2 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -369,6 +369,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
struct buffer_head *bh;
struct object_info root_obj;
unsigned char *b_data;
+ unsigned int blocksize;
struct adfs_sb_info *asb;
struct inode *root;
int ret = -EINVAL;
@@ -420,8 +421,10 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
goto error_free_bh;
}
+ blocksize = 1 << dr->log2secsize;
brelse(bh);
- if (sb_set_blocksize(sb, 1 << dr->log2secsize)) {
+
+ if (sb_set_blocksize(sb, blocksize)) {
bh = sb_bread(sb, ADFS_DISCRECORD / sb->s_blocksize);
if (!bh) {
adfs_error(sb, "couldn't read superblock on "
diff --git a/fs/afs/callback.c b/fs/afs/callback.c
index 5f261fb..4ad7012 100644
--- a/fs/afs/callback.c
+++ b/fs/afs/callback.c
@@ -276,9 +276,9 @@ static void afs_break_one_callback(struct afs_server *server,
struct afs_super_info *as = AFS_FS_S(cbi->sb);
struct afs_volume *volume = as->volume;
- write_lock(&volume->cb_break_lock);
+ write_lock(&volume->cb_v_break_lock);
volume->cb_v_break++;
- write_unlock(&volume->cb_break_lock);
+ write_unlock(&volume->cb_v_break_lock);
} else {
data.volume = NULL;
data.fid = *fid;
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 75d263c..93965f8 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -477,7 +477,7 @@ struct afs_volume {
unsigned int servers_seq; /* Incremented each time ->servers changes */
unsigned cb_v_break; /* Break-everything counter. */
- rwlock_t cb_break_lock;
+ rwlock_t cb_v_break_lock;
afs_voltype_t type; /* type of volume */
short error;
diff --git a/fs/afs/volume.c b/fs/afs/volume.c
index 3037bd0..5ec186e 100644
--- a/fs/afs/volume.c
+++ b/fs/afs/volume.c
@@ -47,6 +47,7 @@ static struct afs_volume *afs_alloc_volume(struct afs_mount_params *params,
atomic_set(&volume->usage, 1);
INIT_LIST_HEAD(&volume->proc_link);
rwlock_init(&volume->servers_lock);
+ rwlock_init(&volume->cb_v_break_lock);
memcpy(volume->name, vldb->name, vldb->name_len + 1);
slist = afs_alloc_server_list(params->cell, params->key, vldb, type_mask);
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index e24c0a6..c841865 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -2732,6 +2732,11 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
* for detecting, at fsync time, if the inode isn't yet in the
* log tree or it's there but not up to date.
*/
+ struct timespec64 now = current_time(inode);
+
+ inode_inc_iversion(inode);
+ inode->i_mtime = now;
+ inode->i_ctime = now;
trans = btrfs_start_transaction(root, 1);
if (IS_ERR(trans)) {
err = PTR_ERR(trans);
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index c1cd3fe..355ff08 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -388,10 +388,31 @@ static noinline int add_async_extent(struct async_cow *cow,
return 0;
}
+/*
+ * Check if the inode has flags compatible with compression
+ */
+static inline bool inode_can_compress(struct inode *inode)
+{
+ if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW ||
+ BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)
+ return false;
+ return true;
+}
+
+/*
+ * Check if the inode needs to be submitted to compression, based on mount
+ * options, defragmentation, properties or heuristics.
+ */
static inline int inode_need_compress(struct inode *inode, u64 start, u64 end)
{
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+ if (!inode_can_compress(inode)) {
+ WARN(IS_ENABLED(CONFIG_BTRFS_DEBUG),
+ KERN_ERR "BTRFS: unexpected compression for ino %llu\n",
+ btrfs_ino(BTRFS_I(inode)));
+ return 0;
+ }
/* force compress */
if (btrfs_test_opt(fs_info, FORCE_COMPRESS))
return 1;
@@ -1596,7 +1617,8 @@ static int run_delalloc_range(void *private_data, struct page *locked_page,
} else if (BTRFS_I(inode)->flags & BTRFS_INODE_PREALLOC && !force_cow) {
ret = run_delalloc_nocow(inode, locked_page, start, end,
page_started, 0, nr_written);
- } else if (!inode_need_compress(inode, start, end)) {
+ } else if (!inode_can_compress(inode) ||
+ !inode_need_compress(inode, start, end)) {
ret = cow_file_range(inode, locked_page, start, end, end,
page_started, nr_written, 1, NULL);
} else {
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index e46e83e..734866a 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -2249,6 +2249,7 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
int ret = 0;
int i;
u64 *i_qgroups;
+ bool committing = false;
struct btrfs_fs_info *fs_info = trans->fs_info;
struct btrfs_root *quota_root;
struct btrfs_qgroup *srcgroup;
@@ -2256,7 +2257,25 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
u32 level_size = 0;
u64 nums;
- mutex_lock(&fs_info->qgroup_ioctl_lock);
+ /*
+ * There are only two callers of this function.
+ *
+ * One in create_subvol() in the ioctl context, which needs to hold
+ * the qgroup_ioctl_lock.
+ *
+ * The other one in create_pending_snapshot() where no other qgroup
+ * code can modify the fs as they all need to either start a new trans
+ * or hold a trans handler, thus we don't need to hold
+ * qgroup_ioctl_lock.
+ * This would avoid long and complex lock chain and make lockdep happy.
+ */
+ spin_lock(&fs_info->trans_lock);
+ if (trans->transaction->state == TRANS_STATE_COMMIT_DOING)
+ committing = true;
+ spin_unlock(&fs_info->trans_lock);
+
+ if (!committing)
+ mutex_lock(&fs_info->qgroup_ioctl_lock);
if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
goto out;
@@ -2420,7 +2439,8 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
unlock:
spin_unlock(&fs_info->qgroup_lock);
out:
- mutex_unlock(&fs_info->qgroup_ioctl_lock);
+ if (!committing)
+ mutex_unlock(&fs_info->qgroup_ioctl_lock);
return ret;
}
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index 258392b..48ddbc1 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -6272,68 +6272,21 @@ static int changed_extent(struct send_ctx *sctx,
{
int ret = 0;
- if (sctx->cur_ino != sctx->cmp_key->objectid) {
-
- if (result == BTRFS_COMPARE_TREE_CHANGED) {
- struct extent_buffer *leaf_l;
- struct extent_buffer *leaf_r;
- struct btrfs_file_extent_item *ei_l;
- struct btrfs_file_extent_item *ei_r;
-
- leaf_l = sctx->left_path->nodes[0];
- leaf_r = sctx->right_path->nodes[0];
- ei_l = btrfs_item_ptr(leaf_l,
- sctx->left_path->slots[0],
- struct btrfs_file_extent_item);
- ei_r = btrfs_item_ptr(leaf_r,
- sctx->right_path->slots[0],
- struct btrfs_file_extent_item);
-
- /*
- * We may have found an extent item that has changed
- * only its disk_bytenr field and the corresponding
- * inode item was not updated. This case happens due to
- * very specific timings during relocation when a leaf
- * that contains file extent items is COWed while
- * relocation is ongoing and its in the stage where it
- * updates data pointers. So when this happens we can
- * safely ignore it since we know it's the same extent,
- * but just at different logical and physical locations
- * (when an extent is fully replaced with a new one, we
- * know the generation number must have changed too,
- * since snapshot creation implies committing the current
- * transaction, and the inode item must have been updated
- * as well).
- * This replacement of the disk_bytenr happens at
- * relocation.c:replace_file_extents() through
- * relocation.c:btrfs_reloc_cow_block().
- */
- if (btrfs_file_extent_generation(leaf_l, ei_l) ==
- btrfs_file_extent_generation(leaf_r, ei_r) &&
- btrfs_file_extent_ram_bytes(leaf_l, ei_l) ==
- btrfs_file_extent_ram_bytes(leaf_r, ei_r) &&
- btrfs_file_extent_compression(leaf_l, ei_l) ==
- btrfs_file_extent_compression(leaf_r, ei_r) &&
- btrfs_file_extent_encryption(leaf_l, ei_l) ==
- btrfs_file_extent_encryption(leaf_r, ei_r) &&
- btrfs_file_extent_other_encoding(leaf_l, ei_l) ==
- btrfs_file_extent_other_encoding(leaf_r, ei_r) &&
- btrfs_file_extent_type(leaf_l, ei_l) ==
- btrfs_file_extent_type(leaf_r, ei_r) &&
- btrfs_file_extent_disk_bytenr(leaf_l, ei_l) !=
- btrfs_file_extent_disk_bytenr(leaf_r, ei_r) &&
- btrfs_file_extent_disk_num_bytes(leaf_l, ei_l) ==
- btrfs_file_extent_disk_num_bytes(leaf_r, ei_r) &&
- btrfs_file_extent_offset(leaf_l, ei_l) ==
- btrfs_file_extent_offset(leaf_r, ei_r) &&
- btrfs_file_extent_num_bytes(leaf_l, ei_l) ==
- btrfs_file_extent_num_bytes(leaf_r, ei_r))
- return 0;
- }
-
- inconsistent_snapshot_error(sctx, result, "extent");
- return -EIO;
- }
+ /*
+ * We have found an extent item that changed without the inode item
+ * having changed. This can happen either after relocation (where the
+ * disk_bytenr of an extent item is replaced at
+ * relocation.c:replace_file_extents()) or after deduplication into a
+ * file in both the parent and send snapshots (where an extent item can
+ * get modified or replaced with a new one). Note that deduplication
+ * updates the inode item, but it only changes the iversion (sequence
+ * field in the inode item) of the inode, so if a file is deduplicated
+ * the same amount of times in both the parent and send snapshots, its
+ * iversion becames the same in both snapshots, whence the inode item is
+ * the same on both snapshots.
+ */
+ if (sctx->cur_ino != sctx->cmp_key->objectid)
+ return 0;
if (!sctx->cur_inode_new_gen && !sctx->cur_inode_deleted) {
if (result != BTRFS_COMPARE_TREE_DELETED)
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index bb8f6c0..f1ca53a 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -2027,6 +2027,16 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)
}
} else {
spin_unlock(&fs_info->trans_lock);
+ /*
+ * The previous transaction was aborted and was already removed
+ * from the list of transactions at fs_info->trans_list. So we
+ * abort to prevent writing a new superblock that reflects a
+ * corrupt state (pointing to trees with unwritten nodes/leafs).
+ */
+ if (test_bit(BTRFS_FS_STATE_TRANS_ABORTED, &fs_info->fs_state)) {
+ ret = -EROFS;
+ goto cleanup_transaction;
+ }
}
extwriter_counter_dec(cur_trans, trans->type);
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 0d5840d20..08c5afa 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -3263,6 +3263,30 @@ int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans,
}
/*
+ * Check if an inode was logged in the current transaction. We can't always rely
+ * on an inode's logged_trans value, because it's an in-memory only field and
+ * therefore not persisted. This means that its value is lost if the inode gets
+ * evicted and loaded again from disk (in which case it has a value of 0, and
+ * certainly it is smaller then any possible transaction ID), when that happens
+ * the full_sync flag is set in the inode's runtime flags, so on that case we
+ * assume eviction happened and ignore the logged_trans value, assuming the
+ * worst case, that the inode was logged before in the current transaction.
+ */
+static bool inode_logged(struct btrfs_trans_handle *trans,
+ struct btrfs_inode *inode)
+{
+ if (inode->logged_trans == trans->transid)
+ return true;
+
+ if (inode->last_trans == trans->transid &&
+ test_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &inode->runtime_flags) &&
+ !test_bit(BTRFS_FS_LOG_RECOVERING, &trans->fs_info->flags))
+ return true;
+
+ return false;
+}
+
+/*
* If both a file and directory are logged, and unlinks or renames are
* mixed in, we have a few interesting corners:
*
@@ -3296,7 +3320,7 @@ int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans,
int bytes_del = 0;
u64 dir_ino = btrfs_ino(dir);
- if (dir->logged_trans < trans->transid)
+ if (!inode_logged(trans, dir))
return 0;
ret = join_running_log_trans(root);
@@ -3401,7 +3425,7 @@ int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans,
u64 index;
int ret;
- if (inode->logged_trans < trans->transid)
+ if (!inode_logged(trans, inode))
return 0;
ret = join_running_log_trans(root);
@@ -5250,9 +5274,19 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
}
}
+ /*
+ * Don't update last_log_commit if we logged that an inode exists after
+ * it was loaded to memory (full_sync bit set).
+ * This is to prevent data loss when we do a write to the inode, then
+ * the inode gets evicted after all delalloc was flushed, then we log
+ * it exists (due to a rename for example) and then fsync it. This last
+ * fsync would do nothing (not logging the extents previously written).
+ */
spin_lock(&inode->lock);
inode->logged_trans = trans->transid;
- inode->last_log_commit = inode->last_sub_trans;
+ if (inode_only != LOG_INODE_EXISTS ||
+ !test_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &inode->runtime_flags))
+ inode->last_log_commit = inode->last_sub_trans;
spin_unlock(&inode->lock);
out_unlock:
mutex_unlock(&inode->log_mutex);
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 2fd0003..6e008bd 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -5040,8 +5040,7 @@ static inline int btrfs_chunk_max_errors(struct map_lookup *map)
if (map->type & (BTRFS_BLOCK_GROUP_RAID1 |
BTRFS_BLOCK_GROUP_RAID10 |
- BTRFS_BLOCK_GROUP_RAID5 |
- BTRFS_BLOCK_GROUP_DUP)) {
+ BTRFS_BLOCK_GROUP_RAID5)) {
max_errors = 1;
} else if (map->type & BTRFS_BLOCK_GROUP_RAID6) {
max_errors = 2;
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
index c7542e8..a11fa0b 100644
--- a/fs/ceph/caps.c
+++ b/fs/ceph/caps.c
@@ -1237,20 +1237,23 @@ static int send_cap_msg(struct cap_msg_args *arg)
}
/*
- * Queue cap releases when an inode is dropped from our cache. Since
- * inode is about to be destroyed, there is no need for i_ceph_lock.
+ * Queue cap releases when an inode is dropped from our cache.
*/
void ceph_queue_caps_release(struct inode *inode)
{
struct ceph_inode_info *ci = ceph_inode(inode);
struct rb_node *p;
+ /* lock i_ceph_lock, because ceph_d_revalidate(..., LOOKUP_RCU)
+ * may call __ceph_caps_issued_mask() on a freeing inode. */
+ spin_lock(&ci->i_ceph_lock);
p = rb_first(&ci->i_caps);
while (p) {
struct ceph_cap *cap = rb_entry(p, struct ceph_cap, ci_node);
p = rb_next(p);
__ceph_remove_cap(cap, true);
}
+ spin_unlock(&ci->i_ceph_lock);
}
/*
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index 582e28f..d8579a5 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -526,7 +526,12 @@ static inline void __ceph_dir_set_complete(struct ceph_inode_info *ci,
long long release_count,
long long ordered_count)
{
- smp_mb__before_atomic();
+ /*
+ * Makes sure operations that setup readdir cache (update page
+ * cache and i_size) are strongly ordered w.r.t. the following
+ * atomic64_set() operations.
+ */
+ smp_mb();
atomic64_set(&ci->i_complete_seq[0], release_count);
atomic64_set(&ci->i_complete_seq[1], ordered_count);
}
diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c
index 5cc8b94..0a2d489 100644
--- a/fs/ceph/xattr.c
+++ b/fs/ceph/xattr.c
@@ -79,7 +79,7 @@ static size_t ceph_vxattrcb_layout(struct ceph_inode_info *ci, char *val,
const char *ns_field = " pool_namespace=";
char buf[128];
size_t len, total_len = 0;
- int ret;
+ ssize_t ret;
pool_ns = ceph_try_get_string(ci->i_layout.pool_ns);
@@ -103,11 +103,8 @@ static size_t ceph_vxattrcb_layout(struct ceph_inode_info *ci, char *val,
if (pool_ns)
total_len += strlen(ns_field) + pool_ns->len;
- if (!size) {
- ret = total_len;
- } else if (total_len > size) {
- ret = -ERANGE;
- } else {
+ ret = total_len;
+ if (size >= total_len) {
memcpy(val, buf, len);
ret = len;
if (pool_name) {
@@ -817,8 +814,11 @@ ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,
if (err)
return err;
err = -ENODATA;
- if (!(vxattr->exists_cb && !vxattr->exists_cb(ci)))
+ if (!(vxattr->exists_cb && !vxattr->exists_cb(ci))) {
err = vxattr->getxattr_cb(ci, value, size);
+ if (size && size < err)
+ err = -ERANGE;
+ }
return err;
}
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index f31339d..c53a2e8 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -563,10 +563,10 @@ static bool
server_unresponsive(struct TCP_Server_Info *server)
{
/*
- * We need to wait 2 echo intervals to make sure we handle such
+ * We need to wait 3 echo intervals to make sure we handle such
* situations right:
* 1s client sends a normal SMB request
- * 2s client gets a response
+ * 3s client gets a response
* 30s echo workqueue job pops, and decides we got a response recently
* and don't need to send another
* ...
@@ -575,9 +575,9 @@ server_unresponsive(struct TCP_Server_Info *server)
*/
if ((server->tcpStatus == CifsGood ||
server->tcpStatus == CifsNeedNegotiate) &&
- time_after(jiffies, server->lstrp + 2 * server->echo_interval)) {
+ time_after(jiffies, server->lstrp + 3 * server->echo_interval)) {
cifs_dbg(VFS, "Server %s has not responded in %lu seconds. Reconnecting...\n",
- server->hostname, (2 * server->echo_interval) / HZ);
+ server->hostname, (3 * server->echo_interval) / HZ);
cifs_reconnect(server);
wake_up(&server->response_q);
return true;
diff --git a/fs/coda/file.c b/fs/coda/file.c
index 1cbc1f2..43d3715 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -27,6 +27,13 @@
#include "coda_linux.h"
#include "coda_int.h"
+struct coda_vm_ops {
+ atomic_t refcnt;
+ struct file *coda_file;
+ const struct vm_operations_struct *host_vm_ops;
+ struct vm_operations_struct vm_ops;
+};
+
static ssize_t
coda_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
{
@@ -61,6 +68,34 @@ coda_file_write_iter(struct kiocb *iocb, struct iov_iter *to)
return ret;
}
+static void
+coda_vm_open(struct vm_area_struct *vma)
+{
+ struct coda_vm_ops *cvm_ops =
+ container_of(vma->vm_ops, struct coda_vm_ops, vm_ops);
+
+ atomic_inc(&cvm_ops->refcnt);
+
+ if (cvm_ops->host_vm_ops && cvm_ops->host_vm_ops->open)
+ cvm_ops->host_vm_ops->open(vma);
+}
+
+static void
+coda_vm_close(struct vm_area_struct *vma)
+{
+ struct coda_vm_ops *cvm_ops =
+ container_of(vma->vm_ops, struct coda_vm_ops, vm_ops);
+
+ if (cvm_ops->host_vm_ops && cvm_ops->host_vm_ops->close)
+ cvm_ops->host_vm_ops->close(vma);
+
+ if (atomic_dec_and_test(&cvm_ops->refcnt)) {
+ vma->vm_ops = cvm_ops->host_vm_ops;
+ fput(cvm_ops->coda_file);
+ kfree(cvm_ops);
+ }
+}
+
static int
coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma)
{
@@ -68,6 +103,8 @@ coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma)
struct coda_inode_info *cii;
struct file *host_file;
struct inode *coda_inode, *host_inode;
+ struct coda_vm_ops *cvm_ops;
+ int ret;
cfi = CODA_FTOC(coda_file);
BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
@@ -76,6 +113,13 @@ coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma)
if (!host_file->f_op->mmap)
return -ENODEV;
+ if (WARN_ON(coda_file != vma->vm_file))
+ return -EIO;
+
+ cvm_ops = kmalloc(sizeof(struct coda_vm_ops), GFP_KERNEL);
+ if (!cvm_ops)
+ return -ENOMEM;
+
coda_inode = file_inode(coda_file);
host_inode = file_inode(host_file);
@@ -89,6 +133,7 @@ coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma)
* the container file on us! */
else if (coda_inode->i_mapping != host_inode->i_mapping) {
spin_unlock(&cii->c_lock);
+ kfree(cvm_ops);
return -EBUSY;
}
@@ -97,7 +142,29 @@ coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma)
cfi->cfi_mapcount++;
spin_unlock(&cii->c_lock);
- return call_mmap(host_file, vma);
+ vma->vm_file = get_file(host_file);
+ ret = call_mmap(vma->vm_file, vma);
+
+ if (ret) {
+ /* if call_mmap fails, our caller will put coda_file so we
+ * should drop the reference to the host_file that we got.
+ */
+ fput(host_file);
+ kfree(cvm_ops);
+ } else {
+ /* here we add redirects for the open/close vm_operations */
+ cvm_ops->host_vm_ops = vma->vm_ops;
+ if (vma->vm_ops)
+ cvm_ops->vm_ops = *vma->vm_ops;
+
+ cvm_ops->vm_ops.open = coda_vm_open;
+ cvm_ops->vm_ops.close = coda_vm_close;
+ cvm_ops->coda_file = coda_file;
+ atomic_set(&cvm_ops->refcnt, 1);
+
+ vma->vm_ops = &cvm_ops->vm_ops;
+ }
+ return ret;
}
int coda_open(struct inode *coda_inode, struct file *coda_file)
@@ -207,4 +274,3 @@ const struct file_operations coda_file_operations = {
.fsync = coda_fsync,
.splice_read = generic_file_splice_read,
};
-
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
index c5234c2..55824cb 100644
--- a/fs/coda/psdev.c
+++ b/fs/coda/psdev.c
@@ -187,8 +187,11 @@ static ssize_t coda_psdev_write(struct file *file, const char __user *buf,
if (req->uc_opcode == CODA_OPEN_BY_FD) {
struct coda_open_by_fd_out *outp =
(struct coda_open_by_fd_out *)req->uc_data;
- if (!outp->oh.result)
+ if (!outp->oh.result) {
outp->fh = fget(outp->fd);
+ if (!outp->fh)
+ return -EBADF;
+ }
}
wake_up(&req->uc_sleep);
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index a9b0094..8f08095 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -894,9 +894,6 @@ COMPATIBLE_IOCTL(PPPIOCDISCONN)
COMPATIBLE_IOCTL(PPPIOCATTCHAN)
COMPATIBLE_IOCTL(PPPIOCGCHAN)
COMPATIBLE_IOCTL(PPPIOCGL2TPSTATS)
-/* PPPOX */
-COMPATIBLE_IOCTL(PPPOEIOCSFWD)
-COMPATIBLE_IOCTL(PPPOEIOCDFWD)
/* Big A */
/* sparc only */
/* Big Q for sound/OSS */
diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
index 4dc788e..203e8b6 100644
--- a/fs/crypto/crypto.c
+++ b/fs/crypto/crypto.c
@@ -159,7 +159,10 @@ int fscrypt_do_page_crypto(const struct inode *inode, fscrypt_direction_t rw,
struct crypto_skcipher *tfm = ci->ci_ctfm;
int res = 0;
- BUG_ON(len == 0);
+ if (WARN_ON_ONCE(len <= 0))
+ return -EINVAL;
+ if (WARN_ON_ONCE(len % FS_CRYPTO_BLOCK_SIZE != 0))
+ return -EINVAL;
fscrypt_generate_iv(&iv, lblk_num, ci);
@@ -243,8 +246,6 @@ struct page *fscrypt_encrypt_page(const struct inode *inode,
struct page *ciphertext_page = page;
int err;
- BUG_ON(len % FS_CRYPTO_BLOCK_SIZE != 0);
-
if (inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES) {
/* with inplace-encryption we just encrypt the page */
err = fscrypt_do_page_crypto(inode, FS_ENCRYPT, lblk_num, page,
@@ -256,7 +257,8 @@ struct page *fscrypt_encrypt_page(const struct inode *inode,
return ciphertext_page;
}
- BUG_ON(!PageLocked(page));
+ if (WARN_ON_ONCE(!PageLocked(page)))
+ return ERR_PTR(-EINVAL);
ctx = fscrypt_get_ctx(inode, gfp_flags);
if (IS_ERR(ctx))
@@ -304,8 +306,9 @@ EXPORT_SYMBOL(fscrypt_encrypt_page);
int fscrypt_decrypt_page(const struct inode *inode, struct page *page,
unsigned int len, unsigned int offs, u64 lblk_num)
{
- if (!(inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES))
- BUG_ON(!PageLocked(page));
+ if (WARN_ON_ONCE(!PageLocked(page) &&
+ !(inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES)))
+ return -EINVAL;
return fscrypt_do_page_crypto(inode, FS_DECRYPT, lblk_num, page, page,
len, offs, GFP_NOFS);
diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c
index bd7eaf9..a4eca6e 100644
--- a/fs/crypto/policy.c
+++ b/fs/crypto/policy.c
@@ -81,6 +81,8 @@ int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg)
if (ret == -ENODATA) {
if (!S_ISDIR(inode->i_mode))
ret = -ENOTDIR;
+ else if (IS_DEADDIR(inode))
+ ret = -ENOENT;
else if (!inode->i_sb->s_cop->empty_dir(inode))
ret = -ENOTEMPTY;
else
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
index a5e4a22..a93ebff 100644
--- a/fs/dlm/lowcomms.c
+++ b/fs/dlm/lowcomms.c
@@ -1630,8 +1630,10 @@ static void clean_writequeues(void)
static void work_stop(void)
{
- destroy_workqueue(recv_workqueue);
- destroy_workqueue(send_workqueue);
+ if (recv_workqueue)
+ destroy_workqueue(recv_workqueue);
+ if (send_workqueue)
+ destroy_workqueue(send_workqueue);
}
static int work_start(void)
@@ -1691,13 +1693,17 @@ static void work_flush(void)
struct hlist_node *n;
struct connection *con;
- flush_workqueue(recv_workqueue);
- flush_workqueue(send_workqueue);
+ if (recv_workqueue)
+ flush_workqueue(recv_workqueue);
+ if (send_workqueue)
+ flush_workqueue(send_workqueue);
do {
ok = 1;
foreach_conn(stop_conn);
- flush_workqueue(recv_workqueue);
- flush_workqueue(send_workqueue);
+ if (recv_workqueue)
+ flush_workqueue(recv_workqueue);
+ if (send_workqueue)
+ flush_workqueue(send_workqueue);
for (i = 0; i < CONN_HASH_SIZE && ok; i++) {
hlist_for_each_entry_safe(con, n,
&connection_hash[i], list) {
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index 4dd842f..708f931 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -1018,8 +1018,10 @@ int ecryptfs_read_and_validate_header_region(struct inode *inode)
rc = ecryptfs_read_lower(file_size, 0, ECRYPTFS_SIZE_AND_MARKER_BYTES,
inode);
- if (rc < ECRYPTFS_SIZE_AND_MARKER_BYTES)
- return rc >= 0 ? -EINVAL : rc;
+ if (rc < 0)
+ return rc;
+ else if (rc < ECRYPTFS_SIZE_AND_MARKER_BYTES)
+ return -EINVAL;
rc = ecryptfs_validate_marker(marker);
if (!rc)
ecryptfs_i_size_init(file_size, inode);
@@ -1381,8 +1383,10 @@ int ecryptfs_read_and_validate_xattr_region(struct dentry *dentry,
ecryptfs_inode_to_lower(inode),
ECRYPTFS_XATTR_NAME, file_size,
ECRYPTFS_SIZE_AND_MARKER_BYTES);
- if (rc < ECRYPTFS_SIZE_AND_MARKER_BYTES)
- return rc >= 0 ? -EINVAL : rc;
+ if (rc < 0)
+ return rc;
+ else if (rc < ECRYPTFS_SIZE_AND_MARKER_BYTES)
+ return -EINVAL;
rc = ecryptfs_validate_marker(marker);
if (!rc)
ecryptfs_i_size_init(file_size, inode);
diff --git a/fs/exec.c b/fs/exec.c
index 77c03ce..aa9d20c 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1826,7 +1826,7 @@ static int __do_execve_file(int fd, struct filename *filename,
membarrier_execve(current);
rseq_execve(current);
acct_update_integrals(current);
- task_numa_free(current);
+ task_numa_free(current, false);
free_bprm(bprm);
kfree(pathbuf);
if (filename)
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
index 0ccd51f..44c2fff 100644
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -108,7 +108,6 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
struct inode *inode = file_inode(file);
struct super_block *sb = inode->i_sb;
struct buffer_head *bh = NULL;
- int dir_has_error = 0;
struct fscrypt_str fstr = FSTR_INIT(NULL, 0);
if (IS_ENCRYPTED(inode)) {
@@ -144,8 +143,6 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
return err;
}
- offset = ctx->pos & (sb->s_blocksize - 1);
-
while (ctx->pos < inode->i_size) {
struct ext4_map_blocks map;
@@ -154,9 +151,18 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
goto errout;
}
cond_resched();
+ offset = ctx->pos & (sb->s_blocksize - 1);
map.m_lblk = ctx->pos >> EXT4_BLOCK_SIZE_BITS(sb);
map.m_len = 1;
err = ext4_map_blocks(NULL, inode, &map, 0);
+ if (err == 0) {
+ /* m_len should never be zero but let's avoid
+ * an infinite loop if it somehow is */
+ if (map.m_len == 0)
+ map.m_len = 1;
+ ctx->pos += map.m_len * sb->s_blocksize;
+ continue;
+ }
if (err > 0) {
pgoff_t index = map.m_pblk >>
(PAGE_SHIFT - inode->i_blkbits);
@@ -175,13 +181,6 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
}
if (!bh) {
- if (!dir_has_error) {
- EXT4_ERROR_FILE(file, 0,
- "directory contains a "
- "hole at offset %llu",
- (unsigned long long) ctx->pos);
- dir_has_error = 1;
- }
/* corrupt size? Maybe no more blocks to read */
if (ctx->pos > inode->i_blocks << 9)
break;
diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h
index 75a5309..ef8fcf7 100644
--- a/fs/ext4/ext4_jbd2.h
+++ b/fs/ext4/ext4_jbd2.h
@@ -361,20 +361,20 @@ static inline int ext4_journal_force_commit(journal_t *journal)
}
static inline int ext4_jbd2_inode_add_write(handle_t *handle,
- struct inode *inode)
+ struct inode *inode, loff_t start_byte, loff_t length)
{
if (ext4_handle_valid(handle))
- return jbd2_journal_inode_add_write(handle,
- EXT4_I(inode)->jinode);
+ return jbd2_journal_inode_ranged_write(handle,
+ EXT4_I(inode)->jinode, start_byte, length);
return 0;
}
static inline int ext4_jbd2_inode_add_wait(handle_t *handle,
- struct inode *inode)
+ struct inode *inode, loff_t start_byte, loff_t length)
{
if (ext4_handle_valid(handle))
- return jbd2_journal_inode_add_wait(handle,
- EXT4_I(inode)->jinode);
+ return jbd2_journal_inode_ranged_wait(handle,
+ EXT4_I(inode)->jinode, start_byte, length);
return 0;
}
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 2c5baa5..f4a24a4 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -165,6 +165,10 @@ static ssize_t ext4_write_checks(struct kiocb *iocb, struct iov_iter *from)
ret = generic_write_checks(iocb, from);
if (ret <= 0)
return ret;
+
+ if (unlikely(IS_IMMUTABLE(inode)))
+ return -EPERM;
+
/*
* If we have encountered a bitmap-format file, the size limit
* is smaller than s_maxbytes, which is for extent-mapped files.
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 094aec6..9b95ec7 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -730,10 +730,16 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
!(flags & EXT4_GET_BLOCKS_ZERO) &&
!ext4_is_quota_file(inode) &&
ext4_should_order_data(inode)) {
+ loff_t start_byte =
+ (loff_t)map->m_lblk << inode->i_blkbits;
+ loff_t length = (loff_t)map->m_len << inode->i_blkbits;
+
if (flags & EXT4_GET_BLOCKS_IO_SUBMIT)
- ret = ext4_jbd2_inode_add_wait(handle, inode);
+ ret = ext4_jbd2_inode_add_wait(handle, inode,
+ start_byte, length);
else
- ret = ext4_jbd2_inode_add_write(handle, inode);
+ ret = ext4_jbd2_inode_add_write(handle, inode,
+ start_byte, length);
if (ret)
return ret;
}
@@ -4123,7 +4129,8 @@ static int __ext4_block_zero_page_range(handle_t *handle,
err = 0;
mark_buffer_dirty(bh);
if (ext4_should_order_data(inode))
- err = ext4_jbd2_inode_add_write(handle, inode);
+ err = ext4_jbd2_inode_add_write(handle, inode, from,
+ length);
}
unlock:
@@ -5563,6 +5570,14 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
return -EIO;
+ if (unlikely(IS_IMMUTABLE(inode)))
+ return -EPERM;
+
+ if (unlikely(IS_APPEND(inode) &&
+ (ia_valid & (ATTR_MODE | ATTR_UID |
+ ATTR_GID | ATTR_TIMES_SET))))
+ return -EPERM;
+
error = setattr_prepare(dentry, attr);
if (error)
return error;
@@ -6262,6 +6277,9 @@ int ext4_page_mkwrite(struct vm_fault *vmf)
get_block_t *get_block;
int retries = 0;
+ if (unlikely(IS_IMMUTABLE(inode)))
+ return VM_FAULT_SIGBUS;
+
sb_start_pagefault(inode->i_sb);
file_update_time(vma->vm_file);
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index e70adf9..a0bbcd1 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -268,6 +268,29 @@ static int uuid_is_zero(__u8 u[16])
}
#endif
+/*
+ * If immutable is set and we are not clearing it, we're not allowed to change
+ * anything else in the inode. Don't error out if we're only trying to set
+ * immutable on an immutable file.
+ */
+static int ext4_ioctl_check_immutable(struct inode *inode, __u32 new_projid,
+ unsigned int flags)
+{
+ struct ext4_inode_info *ei = EXT4_I(inode);
+ unsigned int oldflags = ei->i_flags;
+
+ if (!(oldflags & EXT4_IMMUTABLE_FL) || !(flags & EXT4_IMMUTABLE_FL))
+ return 0;
+
+ if ((oldflags & ~EXT4_IMMUTABLE_FL) != (flags & ~EXT4_IMMUTABLE_FL))
+ return -EPERM;
+ if (ext4_has_feature_project(inode->i_sb) &&
+ __kprojid_val(ei->i_projid) != new_projid)
+ return -EPERM;
+
+ return 0;
+}
+
static int ext4_ioctl_setflags(struct inode *inode,
unsigned int flags)
{
@@ -321,6 +344,20 @@ static int ext4_ioctl_setflags(struct inode *inode,
goto flags_out;
}
+ /*
+ * Wait for all pending directio and then flush all the dirty pages
+ * for this file. The flush marks all the pages readonly, so any
+ * subsequent attempt to write to the file (particularly mmap pages)
+ * will come through the filesystem and fail.
+ */
+ if (S_ISREG(inode->i_mode) && !IS_IMMUTABLE(inode) &&
+ (flags & EXT4_IMMUTABLE_FL)) {
+ inode_dio_wait(inode);
+ err = filemap_write_and_wait(inode->i_mapping);
+ if (err)
+ goto flags_out;
+ }
+
handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
if (IS_ERR(handle)) {
err = PTR_ERR(handle);
@@ -750,7 +787,11 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return err;
inode_lock(inode);
- err = ext4_ioctl_setflags(inode, flags);
+ err = ext4_ioctl_check_immutable(inode,
+ from_kprojid(&init_user_ns, ei->i_projid),
+ flags);
+ if (!err)
+ err = ext4_ioctl_setflags(inode, flags);
inode_unlock(inode);
mnt_drop_write_file(filp);
return err;
@@ -1120,6 +1161,9 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
goto out;
flags = (ei->i_flags & ~EXT4_FL_XFLAG_VISIBLE) |
(flags & EXT4_FL_XFLAG_VISIBLE);
+ err = ext4_ioctl_check_immutable(inode, fa.fsx_projid, flags);
+ if (err)
+ goto out;
err = ext4_ioctl_setflags(inode, flags);
if (err)
goto out;
diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c
index 1083a9f..c7ded4e2 100644
--- a/fs/ext4/move_extent.c
+++ b/fs/ext4/move_extent.c
@@ -390,7 +390,8 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode,
/* Even in case of data=writeback it is reasonable to pin
* inode to transaction, to prevent unexpected data loss */
- *err = ext4_jbd2_inode_add_write(handle, orig_inode);
+ *err = ext4_jbd2_inode_add_write(handle, orig_inode,
+ (loff_t)orig_page_offset << PAGE_SHIFT, replaced_size);
unlock_pages:
unlock_page(pagep[0]);
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 666aff5..3c93a29 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -81,8 +81,18 @@ static struct buffer_head *ext4_append(handle_t *handle,
static int ext4_dx_csum_verify(struct inode *inode,
struct ext4_dir_entry *dirent);
+/*
+ * Hints to ext4_read_dirblock regarding whether we expect a directory
+ * block being read to be an index block, or a block containing
+ * directory entries (and if the latter, whether it was found via a
+ * logical block in an htree index block). This is used to control
+ * what sort of sanity checkinig ext4_read_dirblock() will do on the
+ * directory block read from the storage device. EITHER will means
+ * the caller doesn't know what kind of directory block will be read,
+ * so no specific verification will be done.
+ */
typedef enum {
- EITHER, INDEX, DIRENT
+ EITHER, INDEX, DIRENT, DIRENT_HTREE
} dirblock_type_t;
#define ext4_read_dirblock(inode, block, type) \
@@ -108,11 +118,14 @@ static struct buffer_head *__ext4_read_dirblock(struct inode *inode,
return bh;
}
- if (!bh) {
+ if (!bh && (type == INDEX || type == DIRENT_HTREE)) {
ext4_error_inode(inode, func, line, block,
- "Directory hole found");
+ "Directory hole found for htree %s block",
+ (type == INDEX) ? "index" : "leaf");
return ERR_PTR(-EFSCORRUPTED);
}
+ if (!bh)
+ return NULL;
dirent = (struct ext4_dir_entry *) bh->b_data;
/* Determine whether or not we have an index block */
if (is_dx(inode)) {
@@ -979,7 +992,7 @@ static int htree_dirblock_to_tree(struct file *dir_file,
dxtrace(printk(KERN_INFO "In htree dirblock_to_tree: block %lu\n",
(unsigned long)block));
- bh = ext4_read_dirblock(dir, block, DIRENT);
+ bh = ext4_read_dirblock(dir, block, DIRENT_HTREE);
if (IS_ERR(bh))
return PTR_ERR(bh);
@@ -1509,7 +1522,7 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir,
return (struct buffer_head *) frame;
do {
block = dx_get_block(frame->at);
- bh = ext4_read_dirblock(dir, block, DIRENT);
+ bh = ext4_read_dirblock(dir, block, DIRENT_HTREE);
if (IS_ERR(bh))
goto errout;
@@ -2079,6 +2092,11 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
blocks = dir->i_size >> sb->s_blocksize_bits;
for (block = 0; block < blocks; block++) {
bh = ext4_read_dirblock(dir, block, DIRENT);
+ if (bh == NULL) {
+ bh = ext4_bread(handle, dir, block,
+ EXT4_GET_BLOCKS_CREATE);
+ goto add_to_new_block;
+ }
if (IS_ERR(bh)) {
retval = PTR_ERR(bh);
bh = NULL;
@@ -2099,6 +2117,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
brelse(bh);
}
bh = ext4_append(handle, dir, &block);
+add_to_new_block:
if (IS_ERR(bh)) {
retval = PTR_ERR(bh);
bh = NULL;
@@ -2143,7 +2162,7 @@ static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname,
return PTR_ERR(frame);
entries = frame->entries;
at = frame->at;
- bh = ext4_read_dirblock(dir, dx_get_block(frame->at), DIRENT);
+ bh = ext4_read_dirblock(dir, dx_get_block(frame->at), DIRENT_HTREE);
if (IS_ERR(bh)) {
err = PTR_ERR(bh);
bh = NULL;
@@ -2691,7 +2710,10 @@ bool ext4_empty_dir(struct inode *inode)
EXT4_ERROR_INODE(inode, "invalid size");
return true;
}
- bh = ext4_read_dirblock(inode, 0, EITHER);
+ /* The first directory block must not be a hole,
+ * so treat it as DIRENT_HTREE
+ */
+ bh = ext4_read_dirblock(inode, 0, DIRENT_HTREE);
if (IS_ERR(bh))
return true;
@@ -2713,6 +2735,10 @@ bool ext4_empty_dir(struct inode *inode)
brelse(bh);
lblock = offset >> EXT4_BLOCK_SIZE_BITS(sb);
bh = ext4_read_dirblock(inode, lblock, EITHER);
+ if (bh == NULL) {
+ offset += sb->s_blocksize;
+ continue;
+ }
if (IS_ERR(bh))
return true;
de = (struct ext4_dir_entry_2 *) bh->b_data;
@@ -3256,7 +3282,10 @@ static struct buffer_head *ext4_get_first_dir_block(handle_t *handle,
struct buffer_head *bh;
if (!ext4_has_inline_data(inode)) {
- bh = ext4_read_dirblock(inode, 0, EITHER);
+ /* The first directory block must not be a hole, so
+ * treat it as DIRENT_HTREE
+ */
+ bh = ext4_read_dirblock(inode, 0, DIRENT_HTREE);
if (IS_ERR(bh)) {
*retval = PTR_ERR(bh);
return NULL;
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 93132ac..e8ae480 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -515,7 +515,10 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
inc_page_count(fio->sbi, is_read_io(fio->op) ?
__read_io_type(page): WB_DATA_TYPE(fio->page));
- __f2fs_submit_read_bio(fio->sbi, bio, fio->type);
+ if (is_read_io(fio->op))
+ __f2fs_submit_read_bio(fio->sbi, bio, fio->type);
+ else
+ __submit_bio(fio->sbi, bio, fio->type);
return 0;
}
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 45b45f3..3b7988cb 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -29,6 +29,7 @@
#include "gc.h"
#include "trace.h"
#include <trace/events/f2fs.h>
+#include <trace/events/android_fs.h>
static vm_fault_t f2fs_filemap_fault(struct vm_fault *vmf)
{
@@ -218,6 +219,15 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end,
trace_f2fs_sync_file_enter(inode);
+ if (trace_android_fs_fsync_start_enabled()) {
+ char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+ path = android_fstrace_get_pathname(pathbuf,
+ MAX_TRACE_PATHBUF_LEN, inode);
+ trace_android_fs_fsync_start(inode,
+ current->pid, path, current->comm);
+ }
+
if (S_ISDIR(inode->i_mode))
goto go_write;
@@ -323,6 +333,8 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end,
out:
trace_f2fs_sync_file_exit(inode, cp_reason, datasync, ret);
f2fs_trace_ios(NULL, 1);
+ trace_android_fs_fsync_end(inode, start, end - start);
+
return ret;
}
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 8dee063..ac824f6 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -3393,6 +3393,11 @@ static int read_compacted_summaries(struct f2fs_sb_info *sbi)
seg_i = CURSEG_I(sbi, i);
segno = le32_to_cpu(ckpt->cur_data_segno[i]);
blk_off = le16_to_cpu(ckpt->cur_data_blkoff[i]);
+ if (blk_off > ENTRIES_IN_SUM) {
+ f2fs_bug_on(sbi, 1);
+ f2fs_put_page(page, 1);
+ return -EFAULT;
+ }
seg_i->next_segno = segno;
reset_curseg(sbi, i, 0);
seg_i->alloc_type = ckpt->alloc_type[i];
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 9544e2f..7ee86d8 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -721,6 +721,7 @@ void wbc_detach_inode(struct writeback_control *wbc)
void wbc_account_io(struct writeback_control *wbc, struct page *page,
size_t bytes)
{
+ struct cgroup_subsys_state *css;
int id;
/*
@@ -732,7 +733,12 @@ void wbc_account_io(struct writeback_control *wbc, struct page *page,
if (!wbc->wb)
return;
- id = mem_cgroup_css_from_page(page)->id;
+ css = mem_cgroup_css_from_page(page);
+ /* dead cgroups shouldn't contribute to inode ownership arbitration */
+ if (!(css->flags & CSS_ONLINE))
+ return;
+
+ id = css->id;
if (id == wbc->wb_id) {
wbc->wb_bytes += bytes;
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
index 65ea035..24f86ff 100644
--- a/fs/jbd2/commit.c
+++ b/fs/jbd2/commit.c
@@ -187,14 +187,15 @@ static int journal_wait_on_commit_record(journal_t *journal,
* use writepages() because with dealyed allocation we may be doing
* block allocation in writepages().
*/
-static int journal_submit_inode_data_buffers(struct address_space *mapping)
+static int journal_submit_inode_data_buffers(struct address_space *mapping,
+ loff_t dirty_start, loff_t dirty_end)
{
int ret;
struct writeback_control wbc = {
.sync_mode = WB_SYNC_ALL,
.nr_to_write = mapping->nrpages * 2,
- .range_start = 0,
- .range_end = i_size_read(mapping->host),
+ .range_start = dirty_start,
+ .range_end = dirty_end,
};
ret = generic_writepages(mapping, &wbc);
@@ -218,6 +219,9 @@ static int journal_submit_data_buffers(journal_t *journal,
spin_lock(&journal->j_list_lock);
list_for_each_entry(jinode, &commit_transaction->t_inode_list, i_list) {
+ loff_t dirty_start = jinode->i_dirty_start;
+ loff_t dirty_end = jinode->i_dirty_end;
+
if (!(jinode->i_flags & JI_WRITE_DATA))
continue;
mapping = jinode->i_vfs_inode->i_mapping;
@@ -230,7 +234,8 @@ static int journal_submit_data_buffers(journal_t *journal,
* only allocated blocks here.
*/
trace_jbd2_submit_inode_data(jinode->i_vfs_inode);
- err = journal_submit_inode_data_buffers(mapping);
+ err = journal_submit_inode_data_buffers(mapping, dirty_start,
+ dirty_end);
if (!ret)
ret = err;
spin_lock(&journal->j_list_lock);
@@ -257,12 +262,16 @@ static int journal_finish_inode_data_buffers(journal_t *journal,
/* For locking, see the comment in journal_submit_data_buffers() */
spin_lock(&journal->j_list_lock);
list_for_each_entry(jinode, &commit_transaction->t_inode_list, i_list) {
+ loff_t dirty_start = jinode->i_dirty_start;
+ loff_t dirty_end = jinode->i_dirty_end;
+
if (!(jinode->i_flags & JI_WAIT_DATA))
continue;
jinode->i_flags |= JI_COMMIT_RUNNING;
spin_unlock(&journal->j_list_lock);
- err = filemap_fdatawait_keep_errors(
- jinode->i_vfs_inode->i_mapping);
+ err = filemap_fdatawait_range_keep_errors(
+ jinode->i_vfs_inode->i_mapping, dirty_start,
+ dirty_end);
if (!ret)
ret = err;
spin_lock(&journal->j_list_lock);
@@ -282,6 +291,8 @@ static int journal_finish_inode_data_buffers(journal_t *journal,
&jinode->i_transaction->t_inode_list);
} else {
jinode->i_transaction = NULL;
+ jinode->i_dirty_start = 0;
+ jinode->i_dirty_end = 0;
}
}
spin_unlock(&journal->j_list_lock);
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index e9cf88f..df390a6 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -94,6 +94,8 @@ EXPORT_SYMBOL(jbd2_journal_try_to_free_buffers);
EXPORT_SYMBOL(jbd2_journal_force_commit);
EXPORT_SYMBOL(jbd2_journal_inode_add_write);
EXPORT_SYMBOL(jbd2_journal_inode_add_wait);
+EXPORT_SYMBOL(jbd2_journal_inode_ranged_write);
+EXPORT_SYMBOL(jbd2_journal_inode_ranged_wait);
EXPORT_SYMBOL(jbd2_journal_init_jbd_inode);
EXPORT_SYMBOL(jbd2_journal_release_jbd_inode);
EXPORT_SYMBOL(jbd2_journal_begin_ordered_truncate);
@@ -2588,6 +2590,8 @@ void jbd2_journal_init_jbd_inode(struct jbd2_inode *jinode, struct inode *inode)
jinode->i_next_transaction = NULL;
jinode->i_vfs_inode = inode;
jinode->i_flags = 0;
+ jinode->i_dirty_start = 0;
+ jinode->i_dirty_end = 0;
INIT_LIST_HEAD(&jinode->i_list);
}
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index e20a670..911ff18 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -2500,7 +2500,7 @@ void jbd2_journal_refile_buffer(journal_t *journal, struct journal_head *jh)
* File inode in the inode list of the handle's transaction
*/
static int jbd2_journal_file_inode(handle_t *handle, struct jbd2_inode *jinode,
- unsigned long flags)
+ unsigned long flags, loff_t start_byte, loff_t end_byte)
{
transaction_t *transaction = handle->h_transaction;
journal_t *journal;
@@ -2512,26 +2512,17 @@ static int jbd2_journal_file_inode(handle_t *handle, struct jbd2_inode *jinode,
jbd_debug(4, "Adding inode %lu, tid:%d\n", jinode->i_vfs_inode->i_ino,
transaction->t_tid);
- /*
- * First check whether inode isn't already on the transaction's
- * lists without taking the lock. Note that this check is safe
- * without the lock as we cannot race with somebody removing inode
- * from the transaction. The reason is that we remove inode from the
- * transaction only in journal_release_jbd_inode() and when we commit
- * the transaction. We are guarded from the first case by holding
- * a reference to the inode. We are safe against the second case
- * because if jinode->i_transaction == transaction, commit code
- * cannot touch the transaction because we hold reference to it,
- * and if jinode->i_next_transaction == transaction, commit code
- * will only file the inode where we want it.
- */
- if ((jinode->i_transaction == transaction ||
- jinode->i_next_transaction == transaction) &&
- (jinode->i_flags & flags) == flags)
- return 0;
-
spin_lock(&journal->j_list_lock);
jinode->i_flags |= flags;
+
+ if (jinode->i_dirty_end) {
+ jinode->i_dirty_start = min(jinode->i_dirty_start, start_byte);
+ jinode->i_dirty_end = max(jinode->i_dirty_end, end_byte);
+ } else {
+ jinode->i_dirty_start = start_byte;
+ jinode->i_dirty_end = end_byte;
+ }
+
/* Is inode already attached where we need it? */
if (jinode->i_transaction == transaction ||
jinode->i_next_transaction == transaction)
@@ -2566,12 +2557,28 @@ static int jbd2_journal_file_inode(handle_t *handle, struct jbd2_inode *jinode,
int jbd2_journal_inode_add_write(handle_t *handle, struct jbd2_inode *jinode)
{
return jbd2_journal_file_inode(handle, jinode,
- JI_WRITE_DATA | JI_WAIT_DATA);
+ JI_WRITE_DATA | JI_WAIT_DATA, 0, LLONG_MAX);
}
int jbd2_journal_inode_add_wait(handle_t *handle, struct jbd2_inode *jinode)
{
- return jbd2_journal_file_inode(handle, jinode, JI_WAIT_DATA);
+ return jbd2_journal_file_inode(handle, jinode, JI_WAIT_DATA, 0,
+ LLONG_MAX);
+}
+
+int jbd2_journal_inode_ranged_write(handle_t *handle,
+ struct jbd2_inode *jinode, loff_t start_byte, loff_t length)
+{
+ return jbd2_journal_file_inode(handle, jinode,
+ JI_WRITE_DATA | JI_WAIT_DATA, start_byte,
+ start_byte + length - 1);
+}
+
+int jbd2_journal_inode_ranged_wait(handle_t *handle, struct jbd2_inode *jinode,
+ loff_t start_byte, loff_t length)
+{
+ return jbd2_journal_file_inode(handle, jinode, JI_WAIT_DATA,
+ start_byte, start_byte + length - 1);
}
/*
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index c092661..0a2b59c 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -416,10 +416,10 @@ struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_init)
clp = nfs_match_client(cl_init);
if (clp) {
spin_unlock(&nn->nfs_client_lock);
- if (IS_ERR(clp))
- return clp;
if (new)
new->rpc_ops->free_client(new);
+ if (IS_ERR(clp))
+ return clp;
return nfs_found_client(cl_init, clp);
}
if (new) {
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index a4ea9ab..3baeed0 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1073,6 +1073,100 @@ int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry,
return !nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU);
}
+static int
+nfs_lookup_revalidate_done(struct inode *dir, struct dentry *dentry,
+ struct inode *inode, int error)
+{
+ switch (error) {
+ case 1:
+ dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is valid\n",
+ __func__, dentry);
+ return 1;
+ case 0:
+ nfs_mark_for_revalidate(dir);
+ if (inode && S_ISDIR(inode->i_mode)) {
+ /* Purge readdir caches. */
+ nfs_zap_caches(inode);
+ /*
+ * We can't d_drop the root of a disconnected tree:
+ * its d_hash is on the s_anon list and d_drop() would hide
+ * it from shrink_dcache_for_unmount(), leading to busy
+ * inodes on unmount and further oopses.
+ */
+ if (IS_ROOT(dentry))
+ return 1;
+ }
+ dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is invalid\n",
+ __func__, dentry);
+ return 0;
+ }
+ dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) lookup returned error %d\n",
+ __func__, dentry, error);
+ return error;
+}
+
+static int
+nfs_lookup_revalidate_negative(struct inode *dir, struct dentry *dentry,
+ unsigned int flags)
+{
+ int ret = 1;
+ if (nfs_neg_need_reval(dir, dentry, flags)) {
+ if (flags & LOOKUP_RCU)
+ return -ECHILD;
+ ret = 0;
+ }
+ return nfs_lookup_revalidate_done(dir, dentry, NULL, ret);
+}
+
+static int
+nfs_lookup_revalidate_delegated(struct inode *dir, struct dentry *dentry,
+ struct inode *inode)
+{
+ nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
+ return nfs_lookup_revalidate_done(dir, dentry, inode, 1);
+}
+
+static int
+nfs_lookup_revalidate_dentry(struct inode *dir, struct dentry *dentry,
+ struct inode *inode)
+{
+ struct nfs_fh *fhandle;
+ struct nfs_fattr *fattr;
+ struct nfs4_label *label;
+ int ret;
+
+ ret = -ENOMEM;
+ fhandle = nfs_alloc_fhandle();
+ fattr = nfs_alloc_fattr();
+ label = nfs4_label_alloc(NFS_SERVER(inode), GFP_KERNEL);
+ if (fhandle == NULL || fattr == NULL || IS_ERR(label))
+ goto out;
+
+ ret = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label);
+ if (ret < 0) {
+ if (ret == -ESTALE || ret == -ENOENT)
+ ret = 0;
+ goto out;
+ }
+ ret = 0;
+ if (nfs_compare_fh(NFS_FH(inode), fhandle))
+ goto out;
+ if (nfs_refresh_inode(inode, fattr) < 0)
+ goto out;
+
+ nfs_setsecurity(inode, fattr, label);
+ nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
+
+ /* set a readdirplus hint that we had a cache miss */
+ nfs_force_use_readdirplus(dir);
+ ret = 1;
+out:
+ nfs_free_fattr(fattr);
+ nfs_free_fhandle(fhandle);
+ nfs4_label_free(label);
+ return nfs_lookup_revalidate_done(dir, dentry, inode, ret);
+}
+
/*
* This is called every time the dcache has a lookup hit,
* and we should check whether we can really trust that
@@ -1084,58 +1178,36 @@ int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry,
* If the parent directory is seen to have changed, we throw out the
* cached dentry and do a new lookup.
*/
-static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
+static int
+nfs_do_lookup_revalidate(struct inode *dir, struct dentry *dentry,
+ unsigned int flags)
{
- struct inode *dir;
struct inode *inode;
- struct dentry *parent;
- struct nfs_fh *fhandle = NULL;
- struct nfs_fattr *fattr = NULL;
- struct nfs4_label *label = NULL;
int error;
- if (flags & LOOKUP_RCU) {
- parent = READ_ONCE(dentry->d_parent);
- dir = d_inode_rcu(parent);
- if (!dir)
- return -ECHILD;
- } else {
- parent = dget_parent(dentry);
- dir = d_inode(parent);
- }
nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE);
inode = d_inode(dentry);
- if (!inode) {
- if (nfs_neg_need_reval(dir, dentry, flags)) {
- if (flags & LOOKUP_RCU)
- return -ECHILD;
- goto out_bad;
- }
- goto out_valid;
- }
+ if (!inode)
+ return nfs_lookup_revalidate_negative(dir, dentry, flags);
if (is_bad_inode(inode)) {
- if (flags & LOOKUP_RCU)
- return -ECHILD;
dfprintk(LOOKUPCACHE, "%s: %pd2 has dud inode\n",
__func__, dentry);
goto out_bad;
}
if (NFS_PROTO(dir)->have_delegation(inode, FMODE_READ))
- goto out_set_verifier;
+ return nfs_lookup_revalidate_delegated(dir, dentry, inode);
/* Force a full look up iff the parent directory has changed */
if (!(flags & (LOOKUP_EXCL | LOOKUP_REVAL)) &&
nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU)) {
error = nfs_lookup_verify_inode(inode, flags);
if (error) {
- if (flags & LOOKUP_RCU)
- return -ECHILD;
if (error == -ESTALE)
- goto out_zap_parent;
- goto out_error;
+ nfs_zap_caches(dir);
+ goto out_bad;
}
nfs_advise_use_readdirplus(dir);
goto out_valid;
@@ -1147,81 +1219,45 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
if (NFS_STALE(inode))
goto out_bad;
- error = -ENOMEM;
- fhandle = nfs_alloc_fhandle();
- fattr = nfs_alloc_fattr();
- if (fhandle == NULL || fattr == NULL)
- goto out_error;
-
- label = nfs4_label_alloc(NFS_SERVER(inode), GFP_NOWAIT);
- if (IS_ERR(label))
- goto out_error;
-
trace_nfs_lookup_revalidate_enter(dir, dentry, flags);
- error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label);
+ error = nfs_lookup_revalidate_dentry(dir, dentry, inode);
trace_nfs_lookup_revalidate_exit(dir, dentry, flags, error);
- if (error == -ESTALE || error == -ENOENT)
- goto out_bad;
- if (error)
- goto out_error;
- if (nfs_compare_fh(NFS_FH(inode), fhandle))
- goto out_bad;
- if ((error = nfs_refresh_inode(inode, fattr)) != 0)
- goto out_bad;
+ return error;
+out_valid:
+ return nfs_lookup_revalidate_done(dir, dentry, inode, 1);
+out_bad:
+ if (flags & LOOKUP_RCU)
+ return -ECHILD;
+ return nfs_lookup_revalidate_done(dir, dentry, inode, 0);
+}
- nfs_setsecurity(inode, fattr, label);
+static int
+__nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags,
+ int (*reval)(struct inode *, struct dentry *, unsigned int))
+{
+ struct dentry *parent;
+ struct inode *dir;
+ int ret;
- nfs_free_fattr(fattr);
- nfs_free_fhandle(fhandle);
- nfs4_label_free(label);
-
- /* set a readdirplus hint that we had a cache miss */
- nfs_force_use_readdirplus(dir);
-
-out_set_verifier:
- nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
- out_valid:
if (flags & LOOKUP_RCU) {
+ parent = READ_ONCE(dentry->d_parent);
+ dir = d_inode_rcu(parent);
+ if (!dir)
+ return -ECHILD;
+ ret = reval(dir, dentry, flags);
if (parent != READ_ONCE(dentry->d_parent))
return -ECHILD;
- } else
+ } else {
+ parent = dget_parent(dentry);
+ ret = reval(d_inode(parent), dentry, flags);
dput(parent);
- dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is valid\n",
- __func__, dentry);
- return 1;
-out_zap_parent:
- nfs_zap_caches(dir);
- out_bad:
- WARN_ON(flags & LOOKUP_RCU);
- nfs_free_fattr(fattr);
- nfs_free_fhandle(fhandle);
- nfs4_label_free(label);
- nfs_mark_for_revalidate(dir);
- if (inode && S_ISDIR(inode->i_mode)) {
- /* Purge readdir caches. */
- nfs_zap_caches(inode);
- /*
- * We can't d_drop the root of a disconnected tree:
- * its d_hash is on the s_anon list and d_drop() would hide
- * it from shrink_dcache_for_unmount(), leading to busy
- * inodes on unmount and further oopses.
- */
- if (IS_ROOT(dentry))
- goto out_valid;
}
- dput(parent);
- dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is invalid\n",
- __func__, dentry);
- return 0;
-out_error:
- WARN_ON(flags & LOOKUP_RCU);
- nfs_free_fattr(fattr);
- nfs_free_fhandle(fhandle);
- nfs4_label_free(label);
- dput(parent);
- dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) lookup returned error %d\n",
- __func__, dentry, error);
- return error;
+ return ret;
+}
+
+static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
+{
+ return __nfs_lookup_revalidate(dentry, flags, nfs_do_lookup_revalidate);
}
/*
@@ -1580,62 +1616,55 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
}
EXPORT_SYMBOL_GPL(nfs_atomic_open);
-static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags)
+static int
+nfs4_do_lookup_revalidate(struct inode *dir, struct dentry *dentry,
+ unsigned int flags)
{
struct inode *inode;
- int ret = 0;
if (!(flags & LOOKUP_OPEN) || (flags & LOOKUP_DIRECTORY))
- goto no_open;
+ goto full_reval;
if (d_mountpoint(dentry))
- goto no_open;
- if (NFS_SB(dentry->d_sb)->caps & NFS_CAP_ATOMIC_OPEN_V1)
- goto no_open;
+ goto full_reval;
inode = d_inode(dentry);
/* We can't create new files in nfs_open_revalidate(), so we
* optimize away revalidation of negative dentries.
*/
- if (inode == NULL) {
- struct dentry *parent;
- struct inode *dir;
+ if (inode == NULL)
+ goto full_reval;
- if (flags & LOOKUP_RCU) {
- parent = READ_ONCE(dentry->d_parent);
- dir = d_inode_rcu(parent);
- if (!dir)
- return -ECHILD;
- } else {
- parent = dget_parent(dentry);
- dir = d_inode(parent);
- }
- if (!nfs_neg_need_reval(dir, dentry, flags))
- ret = 1;
- else if (flags & LOOKUP_RCU)
- ret = -ECHILD;
- if (!(flags & LOOKUP_RCU))
- dput(parent);
- else if (parent != READ_ONCE(dentry->d_parent))
- return -ECHILD;
- goto out;
- }
+ if (NFS_PROTO(dir)->have_delegation(inode, FMODE_READ))
+ return nfs_lookup_revalidate_delegated(dir, dentry, inode);
/* NFS only supports OPEN on regular files */
if (!S_ISREG(inode->i_mode))
- goto no_open;
+ goto full_reval;
+
/* We cannot do exclusive creation on a positive dentry */
- if (flags & LOOKUP_EXCL)
- goto no_open;
+ if (flags & (LOOKUP_EXCL | LOOKUP_REVAL))
+ goto reval_dentry;
+
+ /* Check if the directory changed */
+ if (!nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU))
+ goto reval_dentry;
/* Let f_op->open() actually open (and revalidate) the file */
- ret = 1;
+ return 1;
+reval_dentry:
+ if (flags & LOOKUP_RCU)
+ return -ECHILD;
+ return nfs_lookup_revalidate_dentry(dir, dentry, inode);;
-out:
- return ret;
+full_reval:
+ return nfs_do_lookup_revalidate(dir, dentry, flags);
+}
-no_open:
- return nfs_lookup_revalidate(dentry, flags);
+static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags)
+{
+ return __nfs_lookup_revalidate(dentry, flags,
+ nfs4_do_lookup_revalidate);
}
#endif /* CONFIG_NFSV4 */
diff --git a/fs/nfs/flexfilelayout/flexfilelayoutdev.c b/fs/nfs/flexfilelayout/flexfilelayoutdev.c
index 364028c..8da239b 100644
--- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c
+++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c
@@ -307,7 +307,7 @@ int ff_layout_track_ds_error(struct nfs4_flexfile_layout *flo,
if (status == 0)
return 0;
- if (mirror->mirror_ds == NULL)
+ if (IS_ERR_OR_NULL(mirror->mirror_ds))
return -EINVAL;
dserr = kmalloc(sizeof(*dserr), gfp_flags);
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index b65aee4..e4cd3a2 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -1100,6 +1100,7 @@ int nfs_open(struct inode *inode, struct file *filp)
nfs_fscache_open_file(inode, filp);
return 0;
}
+EXPORT_SYMBOL_GPL(nfs_open);
/*
* This function is called whenever some part of NFS notices that
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
index 1348585..61abbb0 100644
--- a/fs/nfs/nfs4file.c
+++ b/fs/nfs/nfs4file.c
@@ -49,7 +49,7 @@ nfs4_file_open(struct inode *inode, struct file *filp)
return err;
if ((openflags & O_ACCMODE) == 3)
- openflags--;
+ return nfs_open(inode, filp);
/* We can't create new files here */
openflags &= ~(O_CREAT|O_EXCL);
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 53cf859..904e08b 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -1243,10 +1243,20 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
atomic_inc(&sp->so_count);
p->o_arg.open_flags = flags;
p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE);
- p->o_arg.umask = current_umask();
p->o_arg.claim = nfs4_map_atomic_open_claim(server, claim);
p->o_arg.share_access = nfs4_map_atomic_open_share(server,
fmode, flags);
+ if (flags & O_CREAT) {
+ p->o_arg.umask = current_umask();
+ p->o_arg.label = nfs4_label_copy(p->a_label, label);
+ if (c->sattr != NULL && c->sattr->ia_valid != 0) {
+ p->o_arg.u.attrs = &p->attrs;
+ memcpy(&p->attrs, c->sattr, sizeof(p->attrs));
+
+ memcpy(p->o_arg.u.verifier.data, c->verf,
+ sizeof(p->o_arg.u.verifier.data));
+ }
+ }
/* don't put an ACCESS op in OPEN compound if O_EXCL, because ACCESS
* will return permission denied for all bits until close */
if (!(flags & O_EXCL)) {
@@ -1270,7 +1280,6 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
p->o_arg.server = server;
p->o_arg.bitmask = nfs4_bitmask(server, label);
p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0];
- p->o_arg.label = nfs4_label_copy(p->a_label, label);
switch (p->o_arg.claim) {
case NFS4_OPEN_CLAIM_NULL:
case NFS4_OPEN_CLAIM_DELEGATE_CUR:
@@ -1283,13 +1292,6 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
p->o_arg.fh = NFS_FH(d_inode(dentry));
}
- if (c != NULL && c->sattr != NULL && c->sattr->ia_valid != 0) {
- p->o_arg.u.attrs = &p->attrs;
- memcpy(&p->attrs, c->sattr, sizeof(p->attrs));
-
- memcpy(p->o_arg.u.verifier.data, c->verf,
- sizeof(p->o_arg.u.verifier.data));
- }
p->c_arg.fh = &p->o_res.fh;
p->c_arg.stateid = &p->o_res.stateid;
p->c_arg.seqid = p->o_arg.seqid;
@@ -1353,12 +1355,20 @@ static bool nfs4_mode_match_open_stateid(struct nfs4_state *state,
return false;
}
-static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode)
+static int can_open_cached(struct nfs4_state *state, fmode_t mode,
+ int open_mode, enum open_claim_type4 claim)
{
int ret = 0;
if (open_mode & (O_EXCL|O_TRUNC))
goto out;
+ switch (claim) {
+ case NFS4_OPEN_CLAIM_NULL:
+ case NFS4_OPEN_CLAIM_FH:
+ goto out;
+ default:
+ break;
+ }
switch (mode & (FMODE_READ|FMODE_WRITE)) {
case FMODE_READ:
ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0
@@ -1751,7 +1761,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
for (;;) {
spin_lock(&state->owner->so_lock);
- if (can_open_cached(state, fmode, open_mode)) {
+ if (can_open_cached(state, fmode, open_mode, claim)) {
update_open_stateflags(state, fmode);
spin_unlock(&state->owner->so_lock);
goto out_return_state;
@@ -2280,7 +2290,8 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
if (data->state != NULL) {
struct nfs_delegation *delegation;
- if (can_open_cached(data->state, data->o_arg.fmode, data->o_arg.open_flags))
+ if (can_open_cached(data->state, data->o_arg.fmode,
+ data->o_arg.open_flags, claim))
goto out_no_action;
rcu_read_lock();
delegation = rcu_dereference(NFS_I(data->state->inode)->delegation);
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 7d9a51e..4931c3a 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -1866,8 +1866,8 @@ pnfs_update_layout(struct inode *ino,
atomic_read(&lo->plh_outstanding) != 0) {
spin_unlock(&ino->i_lock);
lseg = ERR_PTR(wait_var_event_killable(&lo->plh_outstanding,
- atomic_read(&lo->plh_outstanding)));
- if (IS_ERR(lseg) || !list_empty(&lo->plh_segs))
+ !atomic_read(&lo->plh_outstanding)));
+ if (IS_ERR(lseg))
goto out_put_layout_hdr;
pnfs_put_layout_hdr(lo);
goto lookup_again;
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index 29dee96..a18b8d7 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -148,10 +148,13 @@ struct fanotify_event_info *fanotify_alloc_event(struct fsnotify_group *group,
/*
* For queues with unlimited length lost events are not expected and
* can possibly have security implications. Avoid losing events when
- * memory is short.
+ * memory is short. For the limited size queues, avoid OOM killer in the
+ * target monitoring memcg as it may have security repercussion.
*/
if (group->max_events == UINT_MAX)
gfp |= __GFP_NOFAIL;
+ else
+ gfp |= __GFP_RETRY_MAYFAIL;
/* Whoever is interested in the event, pays for the allocation. */
memalloc_use_memcg(group->memcg);
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c
index f4184b4..16b8702 100644
--- a/fs/notify/inotify/inotify_fsnotify.c
+++ b/fs/notify/inotify/inotify_fsnotify.c
@@ -99,9 +99,13 @@ int inotify_handle_event(struct fsnotify_group *group,
i_mark = container_of(inode_mark, struct inotify_inode_mark,
fsn_mark);
- /* Whoever is interested in the event, pays for the allocation. */
+ /*
+ * Whoever is interested in the event, pays for the allocation. Do not
+ * trigger OOM killer in the target monitoring memcg as it may have
+ * security repercussion.
+ */
memalloc_use_memcg(group->memcg);
- event = kmalloc(alloc_len, GFP_KERNEL_ACCOUNT);
+ event = kmalloc(alloc_len, GFP_KERNEL_ACCOUNT | __GFP_RETRY_MAYFAIL);
memalloc_unuse_memcg();
if (unlikely(!event)) {
diff --git a/fs/open.c b/fs/open.c
index 4dbbacc..886da56 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -383,6 +383,25 @@ long do_faccessat(int dfd, const char __user *filename, int mode)
override_cred->cap_permitted;
}
+ /*
+ * The new set of credentials can *only* be used in
+ * task-synchronous circumstances, and does not need
+ * RCU freeing, unless somebody then takes a separate
+ * reference to it.
+ *
+ * NOTE! This is _only_ true because this credential
+ * is used purely for override_creds() that installs
+ * it as the subjective cred. Other threads will be
+ * accessing ->real_cred, not the subjective cred.
+ *
+ * If somebody _does_ make a copy of this (using the
+ * 'get_current_cred()' function), that will clear the
+ * non_rcu field, because now that other user may be
+ * expecting RCU freeing. But normal thread-synchronous
+ * cred accesses will keep things non-RCY.
+ */
+ override_cred->non_rcu = 1;
+
old_cred = override_creds(override_cred);
retry:
res = user_path_at(dfd, filename, lookup_flags, &path);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index c9afcb5..ad4370e 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -206,12 +206,53 @@ static int proc_root_link(struct dentry *dentry, struct path *path)
return result;
}
+/*
+ * If the user used setproctitle(), we just get the string from
+ * user space at arg_start, and limit it to a maximum of one page.
+ */
+static ssize_t get_mm_proctitle(struct mm_struct *mm, char __user *buf,
+ size_t count, unsigned long pos,
+ unsigned long arg_start)
+{
+ char *page;
+ int ret, got;
+
+ if (pos >= PAGE_SIZE)
+ return 0;
+
+ page = (char *)__get_free_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
+
+ ret = 0;
+ got = access_remote_vm(mm, arg_start, page, PAGE_SIZE, FOLL_ANON);
+ if (got > 0) {
+ int len = strnlen(page, got);
+
+ /* Include the NUL character if it was found */
+ if (len < got)
+ len++;
+
+ if (len > pos) {
+ len -= pos;
+ if (len > count)
+ len = count;
+ len -= copy_to_user(buf, page+pos, len);
+ if (!len)
+ len = -EFAULT;
+ ret = len;
+ }
+ }
+ free_page((unsigned long)page);
+ return ret;
+}
+
static ssize_t get_mm_cmdline(struct mm_struct *mm, char __user *buf,
size_t count, loff_t *ppos)
{
unsigned long arg_start, arg_end, env_start, env_end;
unsigned long pos, len;
- char *page;
+ char *page, c;
/* Check if process spawned far enough to have cmdline. */
if (!mm->env_end)
@@ -228,28 +269,42 @@ static ssize_t get_mm_cmdline(struct mm_struct *mm, char __user *buf,
return 0;
/*
- * We have traditionally allowed the user to re-write
- * the argument strings and overflow the end result
- * into the environment section. But only do that if
- * the environment area is contiguous to the arguments.
+ * We allow setproctitle() to overwrite the argument
+ * strings, and overflow past the original end. But
+ * only when it overflows into the environment area.
*/
- if (env_start != arg_end || env_start >= env_end)
+ if (env_start != arg_end || env_end < env_start)
env_start = env_end = arg_end;
-
- /* .. and limit it to a maximum of one page of slop */
- if (env_end >= arg_end + PAGE_SIZE)
- env_end = arg_end + PAGE_SIZE - 1;
+ len = env_end - arg_start;
/* We're not going to care if "*ppos" has high bits set */
- pos = arg_start + *ppos;
-
- /* .. but we do check the result is in the proper range */
- if (pos < arg_start || pos >= env_end)
+ pos = *ppos;
+ if (pos >= len)
+ return 0;
+ if (count > len - pos)
+ count = len - pos;
+ if (!count)
return 0;
- /* .. and we never go past env_end */
- if (env_end - pos < count)
- count = env_end - pos;
+ /*
+ * Magical special case: if the argv[] end byte is not
+ * zero, the user has overwritten it with setproctitle(3).
+ *
+ * Possible future enhancement: do this only once when
+ * pos is 0, and set a flag in the 'struct file'.
+ */
+ if (access_remote_vm(mm, arg_end-1, &c, 1, FOLL_ANON) == 1 && c)
+ return get_mm_proctitle(mm, buf, count, pos, arg_start);
+
+ /*
+ * For the non-setproctitle() case we limit things strictly
+ * to the [arg_start, arg_end[ range.
+ */
+ pos += arg_start;
+ if (pos < arg_start || pos >= arg_end)
+ return 0;
+ if (count > arg_end - pos)
+ count = arg_end - pos;
page = (char *)__get_free_page(GFP_KERNEL);
if (!page)
@@ -259,48 +314,11 @@ static ssize_t get_mm_cmdline(struct mm_struct *mm, char __user *buf,
while (count) {
int got;
size_t size = min_t(size_t, PAGE_SIZE, count);
- long offset;
- /*
- * Are we already starting past the official end?
- * We always include the last byte that is *supposed*
- * to be NUL
- */
- offset = (pos >= arg_end) ? pos - arg_end + 1 : 0;
-
- got = access_remote_vm(mm, pos - offset, page, size + offset, FOLL_ANON);
- if (got <= offset)
+ got = access_remote_vm(mm, pos, page, size, FOLL_ANON);
+ if (got <= 0)
break;
- got -= offset;
-
- /* Don't walk past a NUL character once you hit arg_end */
- if (pos + got >= arg_end) {
- int n = 0;
-
- /*
- * If we started before 'arg_end' but ended up
- * at or after it, we start the NUL character
- * check at arg_end-1 (where we expect the normal
- * EOF to be).
- *
- * NOTE! This is smaller than 'got', because
- * pos + got >= arg_end
- */
- if (pos < arg_end)
- n = arg_end - pos - 1;
-
- /* Cut off at first NUL after 'n' */
- got = n + strnlen(page+n, offset+got-n);
- if (got < offset)
- break;
- got -= offset;
-
- /* Include the NUL if it existed */
- if (got < size)
- got++;
- }
-
- got -= copy_to_user(buf, page+offset, got);
+ got -= copy_to_user(buf, page, got);
if (unlikely(!got)) {
if (!len)
len = -EFAULT;
@@ -2159,9 +2177,12 @@ static int map_files_d_revalidate(struct dentry *dentry, unsigned int flags)
goto out;
if (!dname_to_vma_addr(dentry, &vm_start, &vm_end)) {
- down_read(&mm->mmap_sem);
- exact_vma_exists = !!find_exact_vma(mm, vm_start, vm_end);
- up_read(&mm->mmap_sem);
+ status = down_read_killable(&mm->mmap_sem);
+ if (!status) {
+ exact_vma_exists = !!find_exact_vma(mm, vm_start,
+ vm_end);
+ up_read(&mm->mmap_sem);
+ }
}
mmput(mm);
@@ -2207,8 +2228,11 @@ static int map_files_get_link(struct dentry *dentry, struct path *path)
if (rc)
goto out_mmput;
+ rc = down_read_killable(&mm->mmap_sem);
+ if (rc)
+ goto out_mmput;
+
rc = -ENOENT;
- down_read(&mm->mmap_sem);
vma = find_exact_vma(mm, vm_start, vm_end);
if (vma && vma->vm_file) {
*path = vma->vm_file->f_path;
@@ -2304,7 +2328,11 @@ static struct dentry *proc_map_files_lookup(struct inode *dir,
if (!mm)
goto out_put_task;
- down_read(&mm->mmap_sem);
+ result = ERR_PTR(-EINTR);
+ if (down_read_killable(&mm->mmap_sem))
+ goto out_put_mm;
+
+ result = ERR_PTR(-ENOENT);
vma = find_exact_vma(mm, vm_start, vm_end);
if (!vma)
goto out_no_vma;
@@ -2315,6 +2343,7 @@ static struct dentry *proc_map_files_lookup(struct inode *dir,
out_no_vma:
up_read(&mm->mmap_sem);
+out_put_mm:
mmput(mm);
out_put_task:
put_task_struct(task);
@@ -2356,7 +2385,12 @@ proc_map_files_readdir(struct file *file, struct dir_context *ctx)
mm = get_task_mm(task);
if (!mm)
goto out_put_task;
- down_read(&mm->mmap_sem);
+
+ ret = down_read_killable(&mm->mmap_sem);
+ if (ret) {
+ mmput(mm);
+ goto out_put_task;
+ }
nr_files = 0;
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 7325baa..c95f32b 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -498,6 +498,10 @@ static struct inode *proc_sys_make_inode(struct super_block *sb,
if (root->set_ownership)
root->set_ownership(head, table, &inode->i_uid, &inode->i_gid);
+ else {
+ inode->i_uid = GLOBAL_ROOT_UID;
+ inode->i_gid = GLOBAL_ROOT_GID;
+ }
return inode;
}
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index fac4a09..fe6f135 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -218,7 +218,11 @@ static void *m_start(struct seq_file *m, loff_t *ppos)
if (!mm || !mmget_not_zero(mm))
return NULL;
- down_read(&mm->mmap_sem);
+ if (down_read_killable(&mm->mmap_sem)) {
+ mmput(mm);
+ return ERR_PTR(-EINTR);
+ }
+
hold_task_mempolicy(priv);
priv->tail_vma = get_gate_vma(mm);
@@ -890,7 +894,10 @@ static int show_smaps_rollup(struct seq_file *m, void *v)
memset(&mss, 0, sizeof(mss));
- down_read(&mm->mmap_sem);
+ ret = down_read_killable(&mm->mmap_sem);
+ if (ret)
+ goto out_put_mm;
+
hold_task_mempolicy(priv);
for (vma = priv->mm->mmap; vma; vma = vma->vm_next) {
@@ -907,8 +914,9 @@ static int show_smaps_rollup(struct seq_file *m, void *v)
release_task_mempolicy(priv);
up_read(&mm->mmap_sem);
- mmput(mm);
+out_put_mm:
+ mmput(mm);
out_put_task:
put_task_struct(priv->task);
priv->task = NULL;
@@ -1191,7 +1199,10 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
goto out_mm;
}
- down_read(&mm->mmap_sem);
+ if (down_read_killable(&mm->mmap_sem)) {
+ count = -EINTR;
+ goto out_mm;
+ }
tlb_gather_mmu(&tlb, mm, 0, -1);
if (type == CLEAR_REFS_SOFT_DIRTY) {
for (vma = mm->mmap; vma; vma = vma->vm_next) {
@@ -1598,7 +1609,9 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
/* overflow ? */
if (end < start_vaddr || end > end_vaddr)
end = end_vaddr;
- down_read(&mm->mmap_sem);
+ ret = down_read_killable(&mm->mmap_sem);
+ if (ret)
+ goto out_free;
ret = walk_page_range(start_vaddr, end, &pagemap_walk);
up_read(&mm->mmap_sem);
start_vaddr = end;
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
index 0b63d68d..5161894 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -211,7 +211,11 @@ static void *m_start(struct seq_file *m, loff_t *pos)
if (!mm || !mmget_not_zero(mm))
return NULL;
- down_read(&mm->mmap_sem);
+ if (down_read_killable(&mm->mmap_sem)) {
+ mmput(mm);
+ return ERR_PTR(-EINTR);
+ }
+
/* start from the Nth VMA */
for (p = rb_first(&mm->mm_rb); p; p = rb_next(p))
if (n-- == 0)
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index fc20e06..dd1783e 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -1993,8 +1993,8 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to)
&warn_to[cnt]);
if (ret)
goto over_quota;
- ret = dquot_add_space(transfer_to[cnt], cur_space, rsv_space, 0,
- &warn_to[cnt]);
+ ret = dquot_add_space(transfer_to[cnt], cur_space, rsv_space,
+ DQUOT_SPACE_WARN, &warn_to[cnt]);
if (ret) {
spin_lock(&transfer_to[cnt]->dq_dqb_lock);
dquot_decr_inodes(transfer_to[cnt], inode_usage);
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index ae796e1..4c46ebf 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -470,13 +470,15 @@ static struct buffer_head *udf_getblk(struct inode *inode, udf_pblk_t block,
return NULL;
}
-/* Extend the file by 'blocks' blocks, return the number of extents added */
+/* Extend the file with new blocks totaling 'new_block_bytes',
+ * return the number of extents added
+ */
static int udf_do_extend_file(struct inode *inode,
struct extent_position *last_pos,
struct kernel_long_ad *last_ext,
- sector_t blocks)
+ loff_t new_block_bytes)
{
- sector_t add;
+ uint32_t add;
int count = 0, fake = !(last_ext->extLength & UDF_EXTENT_LENGTH_MASK);
struct super_block *sb = inode->i_sb;
struct kernel_lb_addr prealloc_loc = {};
@@ -486,7 +488,7 @@ static int udf_do_extend_file(struct inode *inode,
/* The previous extent is fake and we should not extend by anything
* - there's nothing to do... */
- if (!blocks && fake)
+ if (!new_block_bytes && fake)
return 0;
iinfo = UDF_I(inode);
@@ -517,13 +519,12 @@ static int udf_do_extend_file(struct inode *inode,
/* Can we merge with the previous extent? */
if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) ==
EXT_NOT_RECORDED_NOT_ALLOCATED) {
- add = ((1 << 30) - sb->s_blocksize -
- (last_ext->extLength & UDF_EXTENT_LENGTH_MASK)) >>
- sb->s_blocksize_bits;
- if (add > blocks)
- add = blocks;
- blocks -= add;
- last_ext->extLength += add << sb->s_blocksize_bits;
+ add = (1 << 30) - sb->s_blocksize -
+ (last_ext->extLength & UDF_EXTENT_LENGTH_MASK);
+ if (add > new_block_bytes)
+ add = new_block_bytes;
+ new_block_bytes -= add;
+ last_ext->extLength += add;
}
if (fake) {
@@ -544,28 +545,27 @@ static int udf_do_extend_file(struct inode *inode,
}
/* Managed to do everything necessary? */
- if (!blocks)
+ if (!new_block_bytes)
goto out;
/* All further extents will be NOT_RECORDED_NOT_ALLOCATED */
last_ext->extLocation.logicalBlockNum = 0;
last_ext->extLocation.partitionReferenceNum = 0;
- add = (1 << (30-sb->s_blocksize_bits)) - 1;
- last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
- (add << sb->s_blocksize_bits);
+ add = (1 << 30) - sb->s_blocksize;
+ last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | add;
/* Create enough extents to cover the whole hole */
- while (blocks > add) {
- blocks -= add;
+ while (new_block_bytes > add) {
+ new_block_bytes -= add;
err = udf_add_aext(inode, last_pos, &last_ext->extLocation,
last_ext->extLength, 1);
if (err)
return err;
count++;
}
- if (blocks) {
+ if (new_block_bytes) {
last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
- (blocks << sb->s_blocksize_bits);
+ new_block_bytes;
err = udf_add_aext(inode, last_pos, &last_ext->extLocation,
last_ext->extLength, 1);
if (err)
@@ -596,6 +596,24 @@ static int udf_do_extend_file(struct inode *inode,
return count;
}
+/* Extend the final block of the file to final_block_len bytes */
+static void udf_do_extend_final_block(struct inode *inode,
+ struct extent_position *last_pos,
+ struct kernel_long_ad *last_ext,
+ uint32_t final_block_len)
+{
+ struct super_block *sb = inode->i_sb;
+ uint32_t added_bytes;
+
+ added_bytes = final_block_len -
+ (last_ext->extLength & (sb->s_blocksize - 1));
+ last_ext->extLength += added_bytes;
+ UDF_I(inode)->i_lenExtents += added_bytes;
+
+ udf_write_aext(inode, last_pos, &last_ext->extLocation,
+ last_ext->extLength, 1);
+}
+
static int udf_extend_file(struct inode *inode, loff_t newsize)
{
@@ -605,10 +623,12 @@ static int udf_extend_file(struct inode *inode, loff_t newsize)
int8_t etype;
struct super_block *sb = inode->i_sb;
sector_t first_block = newsize >> sb->s_blocksize_bits, offset;
+ unsigned long partial_final_block;
int adsize;
struct udf_inode_info *iinfo = UDF_I(inode);
struct kernel_long_ad extent;
- int err;
+ int err = 0;
+ int within_final_block;
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
adsize = sizeof(struct short_ad);
@@ -618,18 +638,8 @@ static int udf_extend_file(struct inode *inode, loff_t newsize)
BUG();
etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);
+ within_final_block = (etype != -1);
- /* File has extent covering the new size (could happen when extending
- * inside a block)? */
- if (etype != -1)
- return 0;
- if (newsize & (sb->s_blocksize - 1))
- offset++;
- /* Extended file just to the boundary of the last file block? */
- if (offset == 0)
- return 0;
-
- /* Truncate is extending the file by 'offset' blocks */
if ((!epos.bh && epos.offset == udf_file_entry_alloc_offset(inode)) ||
(epos.bh && epos.offset == sizeof(struct allocExtDesc))) {
/* File has no extents at all or has empty last
@@ -643,7 +653,22 @@ static int udf_extend_file(struct inode *inode, loff_t newsize)
&extent.extLength, 0);
extent.extLength |= etype << 30;
}
- err = udf_do_extend_file(inode, &epos, &extent, offset);
+
+ partial_final_block = newsize & (sb->s_blocksize - 1);
+
+ /* File has extent covering the new size (could happen when extending
+ * inside a block)?
+ */
+ if (within_final_block) {
+ /* Extending file within the last file block */
+ udf_do_extend_final_block(inode, &epos, &extent,
+ partial_final_block);
+ } else {
+ loff_t add = ((loff_t)offset << sb->s_blocksize_bits) |
+ partial_final_block;
+ err = udf_do_extend_file(inode, &epos, &extent, add);
+ }
+
if (err < 0)
goto out;
err = 0;
@@ -745,6 +770,7 @@ static sector_t inode_getblk(struct inode *inode, sector_t block,
/* Are we beyond EOF? */
if (etype == -1) {
int ret;
+ loff_t hole_len;
isBeyondEOF = true;
if (count) {
if (c)
@@ -760,7 +786,8 @@ static sector_t inode_getblk(struct inode *inode, sector_t block,
startnum = (offset > 0);
}
/* Create extents for the hole between EOF and offset */
- ret = udf_do_extend_file(inode, &prev_epos, laarr, offset);
+ hole_len = (loff_t)offset << inode->i_blkbits;
+ ret = udf_do_extend_file(inode, &prev_epos, laarr, hole_len);
if (ret < 0) {
*err = ret;
newblock = 0;
diff --git a/fs/xfs/libxfs/xfs_ag_resv.c b/fs/xfs/libxfs/xfs_ag_resv.c
index e701ebc..e2ba2a3 100644
--- a/fs/xfs/libxfs/xfs_ag_resv.c
+++ b/fs/xfs/libxfs/xfs_ag_resv.c
@@ -281,7 +281,7 @@ xfs_ag_resv_init(
*/
ask = used = 0;
- mp->m_inotbt_nores = true;
+ mp->m_finobt_nores = true;
error = xfs_refcountbt_calc_reserves(mp, tp, agno, &ask,
&used);
diff --git a/fs/xfs/libxfs/xfs_ialloc_btree.c b/fs/xfs/libxfs/xfs_ialloc_btree.c
index 86c5020..adb2f6d 100644
--- a/fs/xfs/libxfs/xfs_ialloc_btree.c
+++ b/fs/xfs/libxfs/xfs_ialloc_btree.c
@@ -124,7 +124,7 @@ xfs_finobt_alloc_block(
union xfs_btree_ptr *new,
int *stat)
{
- if (cur->bc_mp->m_inotbt_nores)
+ if (cur->bc_mp->m_finobt_nores)
return xfs_inobt_alloc_block(cur, start, new, stat);
return __xfs_inobt_alloc_block(cur, start, new, stat,
XFS_AG_RESV_METADATA);
@@ -157,7 +157,7 @@ xfs_finobt_free_block(
struct xfs_btree_cur *cur,
struct xfs_buf *bp)
{
- if (cur->bc_mp->m_inotbt_nores)
+ if (cur->bc_mp->m_finobt_nores)
return xfs_inobt_free_block(cur, bp);
return __xfs_inobt_free_block(cur, bp, XFS_AG_RESV_METADATA);
}
diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
index a580340..3d213a7 100644
--- a/fs/xfs/xfs_attr_list.c
+++ b/fs/xfs/xfs_attr_list.c
@@ -555,6 +555,7 @@ xfs_attr_put_listent(
attrlist_ent_t *aep;
int arraytop;
+ ASSERT(!context->seen_enough);
ASSERT(!(context->flags & ATTR_KERNOVAL));
ASSERT(context->count >= 0);
ASSERT(context->count < (ATTR_MAX_VALUELEN/8));
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index 211b06e..41ad9ea 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -1080,7 +1080,7 @@ xfs_adjust_extent_unmap_boundaries(
return 0;
}
-static int
+int
xfs_flush_unmap_range(
struct xfs_inode *ip,
xfs_off_t offset,
diff --git a/fs/xfs/xfs_bmap_util.h b/fs/xfs/xfs_bmap_util.h
index 87363d1..9c73d01 100644
--- a/fs/xfs/xfs_bmap_util.h
+++ b/fs/xfs/xfs_bmap_util.h
@@ -76,6 +76,8 @@ int xfs_swap_extents(struct xfs_inode *ip, struct xfs_inode *tip,
xfs_daddr_t xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb);
xfs_extnum_t xfs_bmap_count_leaves(struct xfs_ifork *ifp, xfs_filblks_t *count);
+int xfs_flush_unmap_range(struct xfs_inode *ip, xfs_off_t offset,
+ xfs_off_t len);
int xfs_bmap_count_blocks(struct xfs_trans *tp, struct xfs_inode *ip,
int whichfork, xfs_extnum_t *nextents,
xfs_filblks_t *count);
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index 61a5ad2..2595496 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -517,6 +517,9 @@ xfs_file_dio_aio_write(
}
if (iocb->ki_flags & IOCB_NOWAIT) {
+ /* unaligned dio always waits, bail */
+ if (unaligned_io)
+ return -EAGAIN;
if (!xfs_ilock_nowait(ip, iolock))
return -EAGAIN;
} else {
@@ -529,18 +532,14 @@ xfs_file_dio_aio_write(
count = iov_iter_count(from);
/*
- * If we are doing unaligned IO, wait for all other IO to drain,
- * otherwise demote the lock if we had to take the exclusive lock
- * for other reasons in xfs_file_aio_write_checks.
+ * If we are doing unaligned IO, we can't allow any other overlapping IO
+ * in-flight at the same time or we risk data corruption. Wait for all
+ * other IO to drain before we submit. If the IO is aligned, demote the
+ * iolock if we had to take the exclusive lock in
+ * xfs_file_aio_write_checks() for other reasons.
*/
if (unaligned_io) {
- /* If we are going to wait for other DIO to finish, bail */
- if (iocb->ki_flags & IOCB_NOWAIT) {
- if (atomic_read(&inode->i_dio_count))
- return -EAGAIN;
- } else {
- inode_dio_wait(inode);
- }
+ inode_dio_wait(inode);
} else if (iolock == XFS_IOLOCK_EXCL) {
xfs_ilock_demote(ip, XFS_IOLOCK_EXCL);
iolock = XFS_IOLOCK_SHARED;
@@ -548,6 +547,14 @@ xfs_file_dio_aio_write(
trace_xfs_file_direct_write(ip, count, iocb->ki_pos);
ret = iomap_dio_rw(iocb, from, &xfs_iomap_ops, xfs_dio_write_end_io);
+
+ /*
+ * If unaligned, this is the only IO in-flight. If it has not yet
+ * completed, wait on it before we release the iolock to prevent
+ * subsequent overlapping IO.
+ */
+ if (ret == -EIOCBQUEUED && unaligned_io)
+ inode_dio_wait(inode);
out:
xfs_iunlock(ip, iolock);
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index 7c00b8b..09fd602 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -534,6 +534,7 @@ xfs_fs_reserve_ag_blocks(
int error = 0;
int err2;
+ mp->m_finobt_nores = false;
for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
pag = xfs_perag_get(mp, agno);
err2 = xfs_ag_resv_init(pag, NULL);
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 05db954..5ed84d6 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1332,7 +1332,7 @@ xfs_create_tmpfile(
if (error)
goto out_trans_cancel;
- error = xfs_dir_ialloc(&tp, dp, mode, 1, 0, prid, &ip);
+ error = xfs_dir_ialloc(&tp, dp, mode, 0, 0, prid, &ip);
if (error)
goto out_trans_cancel;
@@ -1754,7 +1754,7 @@ xfs_inactive_ifree(
* now remains allocated and sits on the unlinked list until the fs is
* repaired.
*/
- if (unlikely(mp->m_inotbt_nores)) {
+ if (unlikely(mp->m_finobt_nores)) {
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_ifree,
XFS_IFREE_SPACE_RES(mp), 0, XFS_TRANS_RESERVE,
&tp);
@@ -1907,11 +1907,8 @@ xfs_inactive(
}
/*
- * This is called when the inode's link count goes to 0 or we are creating a
- * tmpfile via O_TMPFILE. In the case of a tmpfile, @ignore_linkcount will be
- * set to true as the link count is dropped to zero by the VFS after we've
- * created the file successfully, so we have to add it to the unlinked list
- * while the link count is non-zero.
+ * This is called when the inode's link count has gone to 0 or we are creating
+ * a tmpfile via O_TMPFILE. The inode @ip must have nlink == 0.
*
* We place the on-disk inode on a list in the AGI. It will be pulled from this
* list when the inode is freed.
@@ -1931,6 +1928,7 @@ xfs_iunlink(
int offset;
int error;
+ ASSERT(VFS_I(ip)->i_nlink == 0);
ASSERT(VFS_I(ip)->i_mode != 0);
/*
@@ -2837,11 +2835,9 @@ xfs_rename_alloc_whiteout(
/*
* Prepare the tmpfile inode as if it were created through the VFS.
- * Otherwise, the link increment paths will complain about nlink 0->1.
- * Drop the link count as done by d_tmpfile(), complete the inode setup
- * and flag it as linkable.
+ * Complete the inode setup and flag it as linkable. nlink is already
+ * zero, so we can skip the drop_nlink.
*/
- drop_nlink(VFS_I(tmpfile));
xfs_setup_iops(tmpfile);
xfs_finish_inode_setup(tmpfile);
VFS_I(tmpfile)->i_state |= I_LINKABLE;
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index f48ffd7..74047bd 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -191,9 +191,18 @@ xfs_generic_create(
xfs_setup_iops(ip);
- if (tmpfile)
+ if (tmpfile) {
+ /*
+ * The VFS requires that any inode fed to d_tmpfile must have
+ * nlink == 1 so that it can decrement the nlink in d_tmpfile.
+ * However, we created the temp file with nlink == 0 because
+ * we're not allowed to put an inode with nlink > 0 on the
+ * unlinked list. Therefore we have to set nlink to 1 so that
+ * d_tmpfile can immediately set it back to zero.
+ */
+ set_nlink(inode, 1);
d_tmpfile(dentry, inode);
- else
+ } else
d_instantiate(dentry, inode);
xfs_finish_inode_setup(ip);
@@ -522,6 +531,10 @@ xfs_vn_getattr(
}
}
+ /*
+ * Note: If you add another clause to set an attribute flag, please
+ * update attributes_mask below.
+ */
if (ip->i_d.di_flags & XFS_DIFLAG_IMMUTABLE)
stat->attributes |= STATX_ATTR_IMMUTABLE;
if (ip->i_d.di_flags & XFS_DIFLAG_APPEND)
@@ -529,6 +542,10 @@ xfs_vn_getattr(
if (ip->i_d.di_flags & XFS_DIFLAG_NODUMP)
stat->attributes |= STATX_ATTR_NODUMP;
+ stat->attributes_mask |= (STATX_ATTR_IMMUTABLE |
+ STATX_ATTR_APPEND |
+ STATX_ATTR_NODUMP);
+
switch (inode->i_mode & S_IFMT) {
case S_IFBLK:
case S_IFCHR:
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index 7964513..7e0bf95 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -127,7 +127,7 @@ typedef struct xfs_mount {
struct mutex m_growlock; /* growfs mutex */
int m_fixedfsid[2]; /* unchanged for life of FS */
uint64_t m_flags; /* global mount flags */
- bool m_inotbt_nores; /* no per-AG finobt resv. */
+ bool m_finobt_nores; /* no per-AG finobt resv. */
int m_ialloc_inos; /* inodes in inode allocation */
int m_ialloc_blks; /* blocks in inode allocation */
int m_ialloc_min_blks;/* min blocks in sparse inode
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
index 7088f44..f3c393f 100644
--- a/fs/xfs/xfs_reflink.c
+++ b/fs/xfs/xfs_reflink.c
@@ -1368,9 +1368,19 @@ xfs_reflink_remap_prep(
if (ret)
goto out_unlock;
- /* Zap any page cache for the destination file's range. */
- truncate_inode_pages_range(&inode_out->i_data, pos_out,
- PAGE_ALIGN(pos_out + *len) - 1);
+ /*
+ * If pos_out > EOF, we may have dirtied blocks between EOF and
+ * pos_out. In that case, we need to extend the flush and unmap to cover
+ * from EOF to the end of the copy length.
+ */
+ if (pos_out > XFS_ISIZE(dest)) {
+ loff_t flen = *len + (pos_out - XFS_ISIZE(dest));
+ ret = xfs_flush_unmap_range(dest, XFS_ISIZE(dest), flen);
+ } else {
+ ret = xfs_flush_unmap_range(dest, pos_out, *len);
+ }
+ if (ret)
+ goto out_unlock;
/* If we're altering the file contents... */
if (!is_dedupe) {
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 207ee30..dce8114 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -1561,6 +1561,13 @@ xfs_mount_alloc(
INIT_DELAYED_WORK(&mp->m_eofblocks_work, xfs_eofblocks_worker);
INIT_DELAYED_WORK(&mp->m_cowblocks_work, xfs_cowblocks_worker);
mp->m_kobj.kobject.kset = xfs_kset;
+ /*
+ * We don't create the finobt per-ag space reservation until after log
+ * recovery, so we must set this to true so that an ifree transaction
+ * started during log recovery will not depend on space reservations
+ * for finobt expansion.
+ */
+ mp->m_finobt_nores = true;
return mp;
}
diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
index 63ee1d5..9a63016 100644
--- a/fs/xfs/xfs_xattr.c
+++ b/fs/xfs/xfs_xattr.c
@@ -129,6 +129,9 @@ __xfs_xattr_put_listent(
char *offset;
int arraytop;
+ if (context->count < 0 || context->seen_enough)
+ return;
+
if (!context->alist)
goto compute_size;
diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h
index 20561a6..d4fb510 100644
--- a/include/asm-generic/bug.h
+++ b/include/asm-generic/bug.h
@@ -104,8 +104,10 @@ extern void warn_slowpath_null(const char *file, const int line);
warn_slowpath_fmt_taint(__FILE__, __LINE__, taint, arg)
#else
extern __printf(1, 2) void __warn_printk(const char *fmt, ...);
-#define __WARN() __WARN_TAINT(TAINT_WARN)
-#define __WARN_printf(arg...) do { __warn_printk(arg); __WARN(); } while (0)
+#define __WARN() do { \
+ printk(KERN_WARNING CUT_HERE); __WARN_TAINT(TAINT_WARN); \
+} while (0)
+#define __WARN_printf(arg...) __WARN_printf_taint(TAINT_WARN, arg)
#define __WARN_printf_taint(taint, arg...) \
do { __warn_printk(arg); __WARN_TAINT(taint); } while (0)
#endif
diff --git a/include/drm/drm_displayid.h b/include/drm/drm_displayid.h
index c0d4df6..9d3b745 100644
--- a/include/drm/drm_displayid.h
+++ b/include/drm/drm_displayid.h
@@ -40,6 +40,7 @@
#define DATA_BLOCK_DISPLAY_INTERFACE 0x0f
#define DATA_BLOCK_STEREO_DISPLAY_INTERFACE 0x10
#define DATA_BLOCK_TILED_DISPLAY 0x12
+#define DATA_BLOCK_CTA 0x81
#define DATA_BLOCK_VENDOR_SPECIFIC 0x7f
@@ -90,4 +91,13 @@ struct displayid_detailed_timing_block {
struct displayid_block base;
struct displayid_detailed_timings_1 timings[0];
};
+
+#define for_each_displayid_db(displayid, block, idx, length) \
+ for ((block) = (struct displayid_block *)&(displayid)[idx]; \
+ (idx) + sizeof(struct displayid_block) <= (length) && \
+ (idx) + sizeof(struct displayid_block) + (block)->num_bytes <= (length) && \
+ (block)->num_bytes > 0; \
+ (idx) += (block)->num_bytes + sizeof(struct displayid_block), \
+ (block) = (struct displayid_block *)&(displayid)[idx])
+
#endif
diff --git a/include/dt-bindings/clock/qcom,dispcc-bengal.h b/include/dt-bindings/clock/qcom,dispcc-bengal.h
index 581f827..223ab5a 100644
--- a/include/dt-bindings/clock/qcom,dispcc-bengal.h
+++ b/include/dt-bindings/clock/qcom,dispcc-bengal.h
@@ -32,8 +32,4 @@
#define DISP_CC_XO_CLK 22
#define DISP_CC_XO_CLK_SRC 23
-/* DISP_CC resets */
-#define DISP_CC_MDSS_CORE_BCR 0
-#define DISP_CC_MDSS_RSCC_BCR 1
-
#endif
diff --git a/include/dt-bindings/clock/qcom,gcc-bengal.h b/include/dt-bindings/clock/qcom,gcc-bengal.h
index 0d403fc..6e07413 100644
--- a/include/dt-bindings/clock/qcom,gcc-bengal.h
+++ b/include/dt-bindings/clock/qcom,gcc-bengal.h
@@ -65,8 +65,6 @@
#define GCC_CAMSS_TOP_AHB_CLK_SRC 55
#define GCC_CFG_NOC_USB3_PRIM_AXI_CLK 56
#define GCC_CPUSS_AHB_CLK 57
-#define GCC_CPUSS_AHB_CLK_SRC 58
-#define GCC_CPUSS_AHB_POSTDIV_CLK_SRC 59
#define GCC_CPUSS_GNOC_CLK 60
#define GCC_CPUSS_THROTTLE_CORE_CLK 61
#define GCC_CPUSS_THROTTLE_XO_CLK 62
@@ -89,123 +87,101 @@
#define GCC_GPU_SNOC_DVM_GFX_CLK 79
#define GCC_GPU_THROTTLE_CORE_CLK 80
#define GCC_GPU_THROTTLE_XO_CLK 81
-#define GCC_MSS_VS_CLK 82
-#define GCC_PDM2_CLK 83
-#define GCC_PDM2_CLK_SRC 84
-#define GCC_PDM_AHB_CLK 85
-#define GCC_PDM_XO4_CLK 86
-#define GCC_PRNG_AHB_CLK 87
-#define GCC_QMIP_CAMERA_NRT_AHB_CLK 88
-#define GCC_QMIP_CAMERA_RT_AHB_CLK 89
-#define GCC_QMIP_CPUSS_CFG_AHB_CLK 90
-#define GCC_QMIP_DISP_AHB_CLK 91
-#define GCC_QMIP_GPU_CFG_AHB_CLK 92
-#define GCC_QMIP_VIDEO_VCODEC_AHB_CLK 93
-#define GCC_QUPV3_WRAP0_CORE_2X_CLK 94
-#define GCC_QUPV3_WRAP0_CORE_CLK 95
-#define GCC_QUPV3_WRAP0_S0_CLK 96
-#define GCC_QUPV3_WRAP0_S0_CLK_SRC 97
-#define GCC_QUPV3_WRAP0_S1_CLK 98
-#define GCC_QUPV3_WRAP0_S1_CLK_SRC 99
-#define GCC_QUPV3_WRAP0_S2_CLK 100
-#define GCC_QUPV3_WRAP0_S2_CLK_SRC 101
-#define GCC_QUPV3_WRAP0_S3_CLK 102
-#define GCC_QUPV3_WRAP0_S3_CLK_SRC 103
-#define GCC_QUPV3_WRAP0_S4_CLK 104
-#define GCC_QUPV3_WRAP0_S4_CLK_SRC 105
-#define GCC_QUPV3_WRAP0_S5_CLK 106
-#define GCC_QUPV3_WRAP0_S5_CLK_SRC 107
-#define GCC_QUPV3_WRAP_0_M_AHB_CLK 108
-#define GCC_QUPV3_WRAP_0_S_AHB_CLK 109
-#define GCC_SDCC1_AHB_CLK 110
-#define GCC_SDCC1_APPS_CLK 111
-#define GCC_SDCC1_APPS_CLK_SRC 112
-#define GCC_SDCC1_ICE_CORE_CLK 113
-#define GCC_SDCC1_ICE_CORE_CLK_SRC 114
-#define GCC_SDCC2_AHB_CLK 115
-#define GCC_SDCC2_APPS_CLK 116
-#define GCC_SDCC2_APPS_CLK_SRC 117
-#define GCC_SYS_NOC_CPUSS_AHB_CLK 118
-#define GCC_SYS_NOC_UFS_PHY_AXI_CLK 119
-#define GCC_SYS_NOC_USB3_PRIM_AXI_CLK 120
-#define GCC_UFS_PHY_AHB_CLK 121
-#define GCC_UFS_PHY_AXI_CLK 122
-#define GCC_UFS_PHY_AXI_CLK_SRC 123
-#define GCC_UFS_PHY_ICE_CORE_CLK 124
-#define GCC_UFS_PHY_ICE_CORE_CLK_SRC 125
-#define GCC_UFS_PHY_PHY_AUX_CLK 126
-#define GCC_UFS_PHY_PHY_AUX_CLK_SRC 127
-#define GCC_UFS_PHY_RX_SYMBOL_0_CLK 128
-#define GCC_UFS_PHY_TX_SYMBOL_0_CLK 129
-#define GCC_UFS_PHY_UNIPRO_CORE_CLK 130
-#define GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC 131
-#define GCC_USB30_PRIM_MASTER_CLK 132
-#define GCC_USB30_PRIM_MASTER_CLK_SRC 133
-#define GCC_USB30_PRIM_MOCK_UTMI_CLK 134
-#define GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC 135
-#define GCC_USB30_PRIM_MOCK_UTMI_POSTDIV_CLK_SRC 136
-#define GCC_USB30_PRIM_SLEEP_CLK 137
-#define GCC_USB3_PRIM_CLKREF_CLK 138
-#define GCC_USB3_PRIM_PHY_AUX_CLK_SRC 139
-#define GCC_USB3_PRIM_PHY_COM_AUX_CLK 140
-#define GCC_USB3_PRIM_PHY_PIPE_CLK 141
-#define GCC_VCODEC0_AXI_CLK 142
-#define GCC_VDDA_VS_CLK 143
-#define GCC_VDDCX_VS_CLK 144
-#define GCC_VDDMX_VS_CLK 145
-#define GCC_VENUS_AHB_CLK 146
-#define GCC_VENUS_CTL_AXI_CLK 147
-#define GCC_VIDEO_AHB_CLK 148
-#define GCC_VIDEO_AXI0_CLK 149
-#define GCC_VIDEO_THROTTLE_CORE_CLK 150
-#define GCC_VIDEO_VCODEC0_SYS_CLK 151
-#define GCC_VIDEO_VENUS_CLK_SRC 152
-#define GCC_VIDEO_VENUS_CTL_CLK 153
-#define GCC_VIDEO_XO_CLK 154
-#define GCC_VS_CTRL_AHB_CLK 155
-#define GCC_VS_CTRL_CLK 156
-#define GCC_VS_CTRL_CLK_SRC 157
-#define GCC_VSENSOR_CLK_SRC 158
-#define GCC_WCSS_VS_CLK 159
-#define GCC_AHB2PHY_CSI_CLK 160
-#define GCC_AHB2PHY_USB_CLK 161
-#define GCC_APC_VS_CLK 162
-#define GCC_BIMC_GPU_AXI_CLK 163
-#define GCC_BOOT_ROM_AHB_CLK 164
-#define GCC_CAM_THROTTLE_NRT_CLK 165
-#define GCC_CAM_THROTTLE_RT_CLK 166
-#define GCC_CAMERA_AHB_CLK 167
-#define GCC_CAMERA_XO_CLK 168
-#define GCC_CAMSS_AXI_CLK 169
-#define GCC_CAMSS_AXI_CLK_SRC 170
-#define GCC_CAMSS_CAMNOC_ATB_CLK 171
-#define GCC_CAMSS_CAMNOC_NTS_XO_CLK 172
-#define GCC_CAMSS_CCI_0_CLK 173
-#define GCC_CAMSS_CCI_CLK_SRC 174
-#define GCC_CAMSS_CPHY_0_CLK 175
-#define GCC_CAMSS_CPHY_1_CLK 176
-#define GCC_CAMSS_CPHY_2_CLK 177
+#define GCC_PDM2_CLK 82
+#define GCC_PDM2_CLK_SRC 83
+#define GCC_PDM_AHB_CLK 84
+#define GCC_PDM_XO4_CLK 85
+#define GCC_PRNG_AHB_CLK 86
+#define GCC_QMIP_CAMERA_NRT_AHB_CLK 87
+#define GCC_QMIP_CAMERA_RT_AHB_CLK 88
+#define GCC_QMIP_CPUSS_CFG_AHB_CLK 89
+#define GCC_QMIP_DISP_AHB_CLK 90
+#define GCC_QMIP_GPU_CFG_AHB_CLK 91
+#define GCC_QMIP_VIDEO_VCODEC_AHB_CLK 92
+#define GCC_QUPV3_WRAP0_CORE_2X_CLK 93
+#define GCC_QUPV3_WRAP0_CORE_CLK 94
+#define GCC_QUPV3_WRAP0_S0_CLK 95
+#define GCC_QUPV3_WRAP0_S0_CLK_SRC 96
+#define GCC_QUPV3_WRAP0_S1_CLK 97
+#define GCC_QUPV3_WRAP0_S1_CLK_SRC 98
+#define GCC_QUPV3_WRAP0_S2_CLK 99
+#define GCC_QUPV3_WRAP0_S2_CLK_SRC 100
+#define GCC_QUPV3_WRAP0_S3_CLK 101
+#define GCC_QUPV3_WRAP0_S3_CLK_SRC 102
+#define GCC_QUPV3_WRAP0_S4_CLK 103
+#define GCC_QUPV3_WRAP0_S4_CLK_SRC 104
+#define GCC_QUPV3_WRAP0_S5_CLK 105
+#define GCC_QUPV3_WRAP0_S5_CLK_SRC 106
+#define GCC_QUPV3_WRAP_0_M_AHB_CLK 107
+#define GCC_QUPV3_WRAP_0_S_AHB_CLK 108
+#define GCC_SDCC1_AHB_CLK 109
+#define GCC_SDCC1_APPS_CLK 110
+#define GCC_SDCC1_APPS_CLK_SRC 111
+#define GCC_SDCC1_ICE_CORE_CLK 112
+#define GCC_SDCC1_ICE_CORE_CLK_SRC 113
+#define GCC_SDCC2_AHB_CLK 114
+#define GCC_SDCC2_APPS_CLK 115
+#define GCC_SDCC2_APPS_CLK_SRC 116
+#define GCC_SYS_NOC_CPUSS_AHB_CLK 117
+#define GCC_SYS_NOC_UFS_PHY_AXI_CLK 118
+#define GCC_SYS_NOC_USB3_PRIM_AXI_CLK 119
+#define GCC_UFS_PHY_AHB_CLK 120
+#define GCC_UFS_PHY_AXI_CLK 121
+#define GCC_UFS_PHY_AXI_CLK_SRC 122
+#define GCC_UFS_PHY_ICE_CORE_CLK 123
+#define GCC_UFS_PHY_ICE_CORE_CLK_SRC 124
+#define GCC_UFS_PHY_PHY_AUX_CLK 125
+#define GCC_UFS_PHY_PHY_AUX_CLK_SRC 126
+#define GCC_UFS_PHY_RX_SYMBOL_0_CLK 127
+#define GCC_UFS_PHY_TX_SYMBOL_0_CLK 128
+#define GCC_UFS_PHY_UNIPRO_CORE_CLK 129
+#define GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC 130
+#define GCC_USB30_PRIM_MASTER_CLK 131
+#define GCC_USB30_PRIM_MASTER_CLK_SRC 132
+#define GCC_USB30_PRIM_MOCK_UTMI_CLK 133
+#define GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC 134
+#define GCC_USB30_PRIM_MOCK_UTMI_POSTDIV_CLK_SRC 135
+#define GCC_USB30_PRIM_SLEEP_CLK 136
+#define GCC_USB3_PRIM_CLKREF_CLK 137
+#define GCC_USB3_PRIM_PHY_AUX_CLK_SRC 138
+#define GCC_USB3_PRIM_PHY_COM_AUX_CLK 139
+#define GCC_USB3_PRIM_PHY_PIPE_CLK 140
+#define GCC_VCODEC0_AXI_CLK 141
+#define GCC_VENUS_AHB_CLK 142
+#define GCC_VENUS_CTL_AXI_CLK 143
+#define GCC_VIDEO_AHB_CLK 144
+#define GCC_VIDEO_AXI0_CLK 145
+#define GCC_VIDEO_THROTTLE_CORE_CLK 146
+#define GCC_VIDEO_VCODEC0_SYS_CLK 147
+#define GCC_VIDEO_VENUS_CLK_SRC 148
+#define GCC_VIDEO_VENUS_CTL_CLK 149
+#define GCC_VIDEO_XO_CLK 150
+#define GCC_AHB2PHY_CSI_CLK 151
+#define GCC_AHB2PHY_USB_CLK 152
+#define GCC_BIMC_GPU_AXI_CLK 153
+#define GCC_BOOT_ROM_AHB_CLK 154
+#define GCC_CAM_THROTTLE_NRT_CLK 155
+#define GCC_CAM_THROTTLE_RT_CLK 156
+#define GCC_CAMERA_AHB_CLK 157
+#define GCC_CAMERA_XO_CLK 158
+#define GCC_CAMSS_AXI_CLK 159
+#define GCC_CAMSS_AXI_CLK_SRC 160
+#define GCC_CAMSS_CAMNOC_ATB_CLK 161
+#define GCC_CAMSS_CAMNOC_NTS_XO_CLK 162
+#define GCC_CAMSS_CCI_0_CLK 163
+#define GCC_CAMSS_CCI_CLK_SRC 164
+#define GCC_CAMSS_CPHY_0_CLK 165
+#define GCC_CAMSS_CPHY_1_CLK 166
+#define GCC_CAMSS_CPHY_2_CLK 167
/* GCC resets */
-#define GCC_CAMSS_OPE_BCR 0
-#define GCC_CAMSS_TFE_BCR 1
-#define GCC_CAMSS_TOP_BCR 2
-#define GCC_GPU_BCR 3
-#define GCC_MMSS_BCR 4
-#define GCC_PDM_BCR 5
-#define GCC_PRNG_BCR 6
-#define GCC_QUPV3_WRAPPER_0_BCR 7
-#define GCC_QUPV3_WRAPPER_1_BCR 8
-#define GCC_QUSB2PHY_PRIM_BCR 9
-#define GCC_QUSB2PHY_SEC_BCR 10
-#define GCC_SDCC1_BCR 11
-#define GCC_SDCC2_BCR 12
-#define GCC_UFS_PHY_BCR 13
-#define GCC_USB30_PRIM_BCR 14
-#define GCC_USB_PHY_CFG_AHB2PHY_BCR 15
-#define GCC_VCODEC0_BCR 16
-#define GCC_VENUS_BCR 17
-#define GCC_VIDEO_INTERFACE_BCR 18
-#define GCC_VS_BCR 19
+#define GCC_QUSB2PHY_PRIM_BCR 0
+#define GCC_QUSB2PHY_SEC_BCR 2
+#define GCC_UFS_PHY_BCR 3
+#define GCC_USB30_PRIM_BCR 4
+#define GCC_USB_PHY_CFG_AHB2PHY_BCR 5
+#define GCC_VCODEC0_BCR 6
+#define GCC_VENUS_BCR 7
+#define GCC_VIDEO_INTERFACE_BCR 8
#endif
diff --git a/include/dt-bindings/clock/qcom,gpucc-bengal.h b/include/dt-bindings/clock/qcom,gpucc-bengal.h
index 19a39e2..fa92b18 100644
--- a/include/dt-bindings/clock/qcom,gpucc-bengal.h
+++ b/include/dt-bindings/clock/qcom,gpucc-bengal.h
@@ -7,25 +7,23 @@
#define _DT_BINDINGS_CLK_QCOM_GPU_CC_BENGAL_H
/* GPU_CC clocks */
-#define GPU_CC_AHB_CLK 0
-#define GPU_CC_CRC_AHB_CLK 1
-#define GPU_CC_CX_APB_CLK 2
-#define GPU_CC_CX_GFX3D_CLK 3
-#define GPU_CC_CX_GFX3D_SLV_CLK 4
-#define GPU_CC_CX_GMU_CLK 5
+#define GPU_CC_PLL0 0
+#define GPU_CC_PLL0_OUT_AUX2 1
+#define GPU_CC_PLL1 2
+#define GPU_CC_PLL1_OUT_AUX 3
+#define GPU_CC_AHB_CLK 4
+#define GPU_CC_CRC_AHB_CLK 5
+#define GPU_CC_CX_GFX3D_CLK 6
+#define GPU_CC_CX_GFX3D_SLV_CLK 7
+#define GPU_CC_CX_GMU_CLK 8
#define GPU_CC_CX_SNOC_DVM_CLK 9
#define GPU_CC_CXO_AON_CLK 10
#define GPU_CC_CXO_CLK 11
#define GPU_CC_GMU_CLK_SRC 12
#define GPU_CC_GX_CXO_CLK 13
#define GPU_CC_GX_GFX3D_CLK 14
+#define GPU_CC_GX_GFX3D_CLK_SRC 15
#define GPU_CC_SLEEP_CLK 16
-
-/* GPU_CC resets */
-#define GPUCC_GPU_CC_CX_BCR 0
-#define GPUCC_GPU_CC_GFX3D_AON_BCR 1
-#define GPUCC_GPU_CC_GMU_BCR 2
-#define GPUCC_GPU_CC_GX_BCR 3
-#define GPUCC_GPU_CC_XO_BCR 4
+#define GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK 17
#endif
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index de8d3d3..b4d23b3 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -326,7 +326,10 @@ void acpi_set_irq_model(enum acpi_irq_model_id model,
#ifdef CONFIG_X86_IO_APIC
extern int acpi_get_override_irq(u32 gsi, int *trigger, int *polarity);
#else
-#define acpi_get_override_irq(gsi, trigger, polarity) (-1)
+static inline int acpi_get_override_irq(u32 gsi, int *trigger, int *polarity)
+{
+ return -1;
+}
#endif
/*
* This function undoes the effect of one call to acpi_register_gsi().
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 741bfb7..3a8a3902 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -505,6 +505,12 @@ struct request_queue {
* various queue flags, see QUEUE_* below
*/
unsigned long queue_flags;
+ /*
+ * Number of contexts that have called blk_set_pm_only(). If this
+ * counter is above zero then only RQF_PM and RQF_PREEMPT requests are
+ * processed.
+ */
+ atomic_t pm_only;
/*
* ida allocated id for this queue. Used to index queues from
@@ -699,8 +705,7 @@ struct request_queue {
#define QUEUE_FLAG_REGISTERED 26 /* queue has been registered to a disk */
#define QUEUE_FLAG_SCSI_PASSTHROUGH 27 /* queue supports SCSI commands */
#define QUEUE_FLAG_QUIESCED 28 /* queue has been quiesced */
-#define QUEUE_FLAG_PREEMPT_ONLY 29 /* only process REQ_PREEMPT requests */
-#define QUEUE_FLAG_INLINECRYPT 30 /* inline encryption support */
+#define QUEUE_FLAG_INLINECRYPT 29 /* inline encryption support */
#define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \
(1 << QUEUE_FLAG_SAME_COMP) | \
@@ -740,12 +745,11 @@ bool blk_queue_flag_test_and_clear(unsigned int flag, struct request_queue *q);
((rq)->cmd_flags & (REQ_FAILFAST_DEV|REQ_FAILFAST_TRANSPORT| \
REQ_FAILFAST_DRIVER))
#define blk_queue_quiesced(q) test_bit(QUEUE_FLAG_QUIESCED, &(q)->queue_flags)
-#define blk_queue_preempt_only(q) \
- test_bit(QUEUE_FLAG_PREEMPT_ONLY, &(q)->queue_flags)
+#define blk_queue_pm_only(q) atomic_read(&(q)->pm_only)
#define blk_queue_fua(q) test_bit(QUEUE_FLAG_FUA, &(q)->queue_flags)
-extern int blk_set_preempt_only(struct request_queue *q);
-extern void blk_clear_preempt_only(struct request_queue *q);
+extern void blk_set_pm_only(struct request_queue *q);
+extern void blk_clear_pm_only(struct request_queue *q);
static inline int queue_in_flight(struct request_queue *q)
{
diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h
index 6984e7e..e78086c 100644
--- a/include/linux/cgroup-defs.h
+++ b/include/linux/cgroup-defs.h
@@ -209,6 +209,7 @@ struct css_set {
*/
struct list_head tasks;
struct list_head mg_tasks;
+ struct list_head dying_tasks;
/* all css_task_iters currently walking this cset */
struct list_head task_iters;
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index f19635e..7fd81b7 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -43,6 +43,9 @@
/* walk all threaded css_sets in the domain */
#define CSS_TASK_ITER_THREADED (1U << 1)
+/* internal flags */
+#define CSS_TASK_ITER_SKIPPED (1U << 16)
+
/* a css_task_iter should be treated as an opaque object */
struct css_task_iter {
struct cgroup_subsys *ss;
@@ -57,6 +60,7 @@ struct css_task_iter {
struct list_head *task_pos;
struct list_head *tasks_head;
struct list_head *mg_tasks_head;
+ struct list_head *dying_tasks_head;
struct css_set *cur_cset;
struct css_set *cur_dcset;
diff --git a/include/linux/coda.h b/include/linux/coda.h
index d30209b..0ca0c83 100644
--- a/include/linux/coda.h
+++ b/include/linux/coda.h
@@ -58,8 +58,7 @@ Mellon the rights to redistribute these changes without encumbrance.
#ifndef _CODA_HEADER_
#define _CODA_HEADER_
-#if defined(__linux__)
typedef unsigned long long u_quad_t;
-#endif
+
#include <uapi/linux/coda.h>
#endif
diff --git a/include/linux/coda_psdev.h b/include/linux/coda_psdev.h
index 1517095..57d2b2f 100644
--- a/include/linux/coda_psdev.h
+++ b/include/linux/coda_psdev.h
@@ -19,6 +19,17 @@ struct venus_comm {
struct mutex vc_mutex;
};
+/* messages between coda filesystem in kernel and Venus */
+struct upc_req {
+ struct list_head uc_chain;
+ caddr_t uc_data;
+ u_short uc_flags;
+ u_short uc_inSize; /* Size is at most 5000 bytes */
+ u_short uc_outSize;
+ u_short uc_opcode; /* copied from data to save lookup */
+ int uc_unique;
+ wait_queue_head_t uc_sleep; /* process' wait queue */
+};
static inline struct venus_comm *coda_vcp(struct super_block *sb)
{
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 037eb86..707235f 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -119,10 +119,10 @@ enum cpuhp_state {
CPUHP_AP_PERF_ARM_ACPI_STARTING,
CPUHP_AP_PERF_ARM_STARTING,
CPUHP_AP_ARM_L2X0_STARTING,
+ CPUHP_AP_EXYNOS4_MCT_TIMER_STARTING,
CPUHP_AP_ARM_ARCH_TIMER_STARTING,
CPUHP_AP_ARM_GLOBAL_TIMER_STARTING,
CPUHP_AP_JCORE_TIMER_STARTING,
- CPUHP_AP_EXYNOS4_MCT_TIMER_STARTING,
CPUHP_AP_ARM_TWD_STARTING,
CPUHP_AP_QCOM_TIMER_STARTING,
CPUHP_AP_QCOM_CPUFREQ_STARTING,
@@ -178,6 +178,7 @@ enum cpuhp_state {
CPUHP_AP_WORKQUEUE_ONLINE,
CPUHP_AP_RCUTREE_ONLINE,
CPUHP_AP_NOTIFY_PERF_ONLINE,
+ CPUHP_AP_BASE_CACHEINFO_ONLINE,
CPUHP_AP_ONLINE_DYN,
CPUHP_AP_ONLINE_DYN_END = CPUHP_AP_ONLINE_DYN + 30,
CPUHP_AP_X86_HPET_ONLINE,
diff --git a/include/linux/cred.h b/include/linux/cred.h
index 7eed610..1dc351d 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -150,7 +150,11 @@ struct cred {
struct user_struct *user; /* real user ID subscription */
struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */
struct group_info *group_info; /* supplementary groups for euid/fsgid */
- struct rcu_head rcu; /* RCU deletion hook */
+ /* RCU deletion */
+ union {
+ int non_rcu; /* Can we skip RCU deletion? */
+ struct rcu_head rcu; /* RCU deletion hook */
+ };
} __randomize_layout;
extern void __put_cred(struct cred *);
@@ -248,6 +252,7 @@ static inline const struct cred *get_cred(const struct cred *cred)
{
struct cred *nonconst_cred = (struct cred *) cred;
validate_creds(cred);
+ nonconst_cred->non_rcu = 0;
return get_new_cred(nonconst_cred);
}
diff --git a/include/linux/device.h b/include/linux/device.h
index cf133f5..7e5c1e5 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -1336,6 +1336,7 @@ extern int (*platform_notify_remove)(struct device *dev);
*/
extern struct device *get_device(struct device *dev);
extern void put_device(struct device *dev);
+extern bool kill_device(struct device *dev);
#ifdef CONFIG_DEVTMPFS
extern int devtmpfs_create_node(struct device *dev);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index c3eee55..f083217 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2674,6 +2674,8 @@ extern int filemap_flush(struct address_space *);
extern int filemap_fdatawait_keep_errors(struct address_space *mapping);
extern int filemap_fdatawait_range(struct address_space *, loff_t lstart,
loff_t lend);
+extern int filemap_fdatawait_range_keep_errors(struct address_space *mapping,
+ loff_t start_byte, loff_t end_byte);
static inline int filemap_fdatawait(struct address_space *mapping)
{
diff --git a/include/linux/host1x.h b/include/linux/host1x.h
index 89110d8..aef6e2f 100644
--- a/include/linux/host1x.h
+++ b/include/linux/host1x.h
@@ -310,6 +310,8 @@ struct host1x_device {
struct list_head clients;
bool registered;
+
+ struct device_dma_parameters dma_parms;
};
static inline struct host1x_device *to_host1x_device(struct device *dev)
diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h
index ba7a9b0..24e9b36 100644
--- a/include/linux/if_pppox.h
+++ b/include/linux/if_pppox.h
@@ -84,6 +84,9 @@ extern int register_pppox_proto(int proto_num, const struct pppox_proto *pp);
extern void unregister_pppox_proto(int proto_num);
extern void pppox_unbind_sock(struct sock *sk);/* delete ppp-channel binding */
extern int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
+extern int pppox_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
+
+#define PPPOEIOCSFWD32 _IOW(0xB1 ,0, compat_size_t)
/* PPPoX socket states */
enum {
diff --git a/include/linux/iova.h b/include/linux/iova.h
index 3acb4f5..c9fb031 100644
--- a/include/linux/iova.h
+++ b/include/linux/iova.h
@@ -157,6 +157,7 @@ struct iova *reserve_iova(struct iova_domain *iovad, unsigned long pfn_lo,
void copy_reserved_iova(struct iova_domain *from, struct iova_domain *to);
void init_iova_domain(struct iova_domain *iovad, unsigned long granule,
unsigned long start_pfn);
+bool has_iova_flush_queue(struct iova_domain *iovad);
int init_iova_flush_queue(struct iova_domain *iovad,
iova_flush_cb flush_cb, iova_entry_dtor entry_dtor);
struct iova *find_iova(struct iova_domain *iovad, unsigned long pfn);
@@ -237,6 +238,11 @@ static inline void init_iova_domain(struct iova_domain *iovad,
{
}
+static inline bool has_iova_flush_queue(struct iova_domain *iovad)
+{
+ return false;
+}
+
static inline int init_iova_flush_queue(struct iova_domain *iovad,
iova_flush_cb flush_cb,
iova_entry_dtor entry_dtor)
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
index 583b82b..1cf1b9b 100644
--- a/include/linux/jbd2.h
+++ b/include/linux/jbd2.h
@@ -454,6 +454,22 @@ struct jbd2_inode {
* @i_flags: Flags of inode [j_list_lock]
*/
unsigned long i_flags;
+
+ /**
+ * @i_dirty_start:
+ *
+ * Offset in bytes where the dirty range for this inode starts.
+ * [j_list_lock]
+ */
+ loff_t i_dirty_start;
+
+ /**
+ * @i_dirty_end:
+ *
+ * Inclusive offset in bytes where the dirty range for this inode
+ * ends. [j_list_lock]
+ */
+ loff_t i_dirty_end;
};
struct jbd2_revoke_table_s;
@@ -1399,6 +1415,12 @@ extern int jbd2_journal_force_commit(journal_t *);
extern int jbd2_journal_force_commit_nested(journal_t *);
extern int jbd2_journal_inode_add_write(handle_t *handle, struct jbd2_inode *inode);
extern int jbd2_journal_inode_add_wait(handle_t *handle, struct jbd2_inode *inode);
+extern int jbd2_journal_inode_ranged_write(handle_t *handle,
+ struct jbd2_inode *inode, loff_t start_byte,
+ loff_t length);
+extern int jbd2_journal_inode_ranged_wait(handle_t *handle,
+ struct jbd2_inode *inode, loff_t start_byte,
+ loff_t length);
extern int jbd2_journal_begin_ordered_truncate(journal_t *journal,
struct jbd2_inode *inode, loff_t new_size);
extern void jbd2_journal_init_jbd_inode(struct jbd2_inode *jinode, struct inode *inode);
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 3d83ebb..f6f94e5 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -118,7 +118,8 @@
#define DIV_ROUND_DOWN_ULL(ll, d) \
({ unsigned long long _tmp = (ll); do_div(_tmp, d); _tmp; })
-#define DIV_ROUND_UP_ULL(ll, d) DIV_ROUND_DOWN_ULL((ll) + (d) - 1, (d))
+#define DIV_ROUND_UP_ULL(ll, d) \
+ DIV_ROUND_DOWN_ULL((unsigned long long)(ll) + (d) - 1, (d))
#if BITS_PER_LONG == 32
# define DIV_ROUND_UP_SECTOR_T(ll,d) DIV_ROUND_UP_ULL(ll, d)
diff --git a/include/linux/mhi.h b/include/linux/mhi.h
index 93a4778..1c4b37c 100644
--- a/include/linux/mhi.h
+++ b/include/linux/mhi.h
@@ -17,24 +17,24 @@ struct mhi_buf_info;
* enum MHI_CB - MHI callback
* @MHI_CB_IDLE: MHI entered idle state
* @MHI_CB_PENDING_DATA: New data available for client to process
+ * @MHI_CB_DTR_SIGNAL: DTR signaling update
* @MHI_CB_LPM_ENTER: MHI host entered low power mode
* @MHI_CB_LPM_EXIT: MHI host about to exit low power mode
* @MHI_CB_EE_RDDM: MHI device entered RDDM execution enviornment
* @MHI_CB_EE_MISSION_MODE: MHI device entered Mission Mode ee
* @MHI_CB_SYS_ERROR: MHI device enter error state (may recover)
* @MHI_CB_FATAL_ERROR: MHI device entered fatal error
- * @MHI_CB_BW_REQ: Received a bandwidth switch request from device
*/
enum MHI_CB {
MHI_CB_IDLE,
MHI_CB_PENDING_DATA,
+ MHI_CB_DTR_SIGNAL,
MHI_CB_LPM_ENTER,
MHI_CB_LPM_EXIT,
MHI_CB_EE_RDDM,
MHI_CB_EE_MISSION_MODE,
MHI_CB_SYS_ERROR,
MHI_CB_FATAL_ERROR,
- MHI_CB_BW_REQ,
};
/**
@@ -119,10 +119,12 @@ enum mhi_dev_state {
* struct mhi_link_info - bw requirement
* target_link_speed - as defined by TLS bits in LinkControl reg
* target_link_width - as defined by NLW bits in LinkStatus reg
+ * sequence_num - used by device to track bw requests sent to host
*/
struct mhi_link_info {
unsigned int target_link_speed;
unsigned int target_link_width;
+ int sequence_num;
};
/**
@@ -198,6 +200,7 @@ struct mhi_controller {
void __iomem *bhi;
void __iomem *bhie;
void __iomem *wake_db;
+ void __iomem *bw_scale_db;
/* device topology */
u32 dev_id;
@@ -240,6 +243,7 @@ struct mhi_controller {
u32 msi_allocated;
int *irq; /* interrupt table */
struct mhi_event *mhi_event;
+ struct list_head lp_ev_rings; /* low priority event rings */
/* cmd rings */
struct mhi_cmd *mhi_cmd;
@@ -278,6 +282,7 @@ struct mhi_controller {
struct work_struct st_worker;
struct work_struct fw_worker;
struct work_struct syserr_worker;
+ struct work_struct low_priority_worker;
wait_queue_head_t state_event;
/* shadow functions */
@@ -297,6 +302,8 @@ struct mhi_controller {
void (*unmap_single)(struct mhi_controller *mhi_cntrl,
struct mhi_buf_info *buf);
void (*tsync_log)(struct mhi_controller *mhi_cntrl, u64 remote_time);
+ int (*bw_scale)(struct mhi_controller *mhi_cntrl,
+ struct mhi_link_info *link_info);
/* channel to control DTR messaging */
struct mhi_device *dtr_dev;
diff --git a/include/linux/mlx5/fs.h b/include/linux/mlx5/fs.h
index 804516e..3386399 100644
--- a/include/linux/mlx5/fs.h
+++ b/include/linux/mlx5/fs.h
@@ -188,6 +188,7 @@ int mlx5_modify_rule_destination(struct mlx5_flow_handle *handler,
struct mlx5_fc *mlx5_flow_rule_counter(struct mlx5_flow_handle *handler);
struct mlx5_fc *mlx5_fc_create(struct mlx5_core_dev *dev, bool aging);
void mlx5_fc_destroy(struct mlx5_core_dev *dev, struct mlx5_fc *counter);
+u64 mlx5_fc_query_lastuse(struct mlx5_fc *counter);
void mlx5_fc_query_cached(struct mlx5_fc *counter,
u64 *bytes, u64 *packets, u64 *lastuse);
int mlx5_fc_query(struct mlx5_core_dev *dev, struct mlx5_fc *counter,
diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h
index f043d65..177f11c 100644
--- a/include/linux/mlx5/mlx5_ifc.h
+++ b/include/linux/mlx5/mlx5_ifc.h
@@ -5623,7 +5623,12 @@ struct mlx5_ifc_modify_cq_in_bits {
struct mlx5_ifc_cqc_bits cq_context;
- u8 reserved_at_280[0x600];
+ u8 reserved_at_280[0x60];
+
+ u8 cq_umem_valid[0x1];
+ u8 reserved_at_2e1[0x1f];
+
+ u8 reserved_at_300[0x580];
u8 pas[0][0x40];
};
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 8c416cc..c2e5cf8 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -1049,6 +1049,11 @@ static inline int in_software_context(struct perf_event *event)
return event->ctx->pmu->task_ctx_nr == perf_sw_context;
}
+static inline int is_exclusive_pmu(struct pmu *pmu)
+{
+ return pmu->capabilities & PERF_PMU_CAP_EXCLUSIVE;
+}
+
extern struct static_key perf_swevent_enabled[PERF_COUNT_SW_MAX];
extern void ___perf_sw_event(u32, u64, struct pt_regs *, u64);
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index e102c5b..68cbe11 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -620,7 +620,7 @@ static inline void rcu_preempt_sleep_check(void) { }
* read-side critical sections may be preempted and they may also block, but
* only when acquiring spinlocks that are subject to priority inheritance.
*/
-static inline void rcu_read_lock(void)
+static __always_inline void rcu_read_lock(void)
{
__rcu_read_lock();
__acquire(RCU);
diff --git a/include/linux/sched.h b/include/linux/sched.h
index eceacc2..6b99745 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1201,7 +1201,15 @@ struct task_struct {
u64 last_sum_exec_runtime;
struct callback_head numa_work;
- struct numa_group *numa_group;
+ /*
+ * This pointer is only modified for current in syscall and
+ * pagefault context (and for tasks being destroyed), so it can be read
+ * from any of the following contexts:
+ * - RCU read-side critical section
+ * - current->numa_group from everywhere
+ * - task's runqueue locked, task not running
+ */
+ struct numa_group __rcu *numa_group;
/*
* numa_faults is an array split into four regions:
diff --git a/include/linux/sched/numa_balancing.h b/include/linux/sched/numa_balancing.h
index e7dd04a..3988762 100644
--- a/include/linux/sched/numa_balancing.h
+++ b/include/linux/sched/numa_balancing.h
@@ -19,7 +19,7 @@
extern void task_numa_fault(int last_node, int node, int pages, int flags);
extern pid_t task_numa_group_id(struct task_struct *p);
extern void set_numabalancing_state(bool enabled);
-extern void task_numa_free(struct task_struct *p);
+extern void task_numa_free(struct task_struct *p, bool final);
extern bool should_numa_migrate_memory(struct task_struct *p, struct page *page,
int src_nid, int dst_cpu);
#else
@@ -34,7 +34,7 @@ static inline pid_t task_numa_group_id(struct task_struct *p)
static inline void set_numabalancing_state(bool enabled)
{
}
-static inline void task_numa_free(struct task_struct *p)
+static inline void task_numa_free(struct task_struct *p, bool final)
{
}
static inline bool should_numa_migrate_memory(struct task_struct *p,
diff --git a/include/linux/usb/usb_qdss.h b/include/linux/usb/usb_qdss.h
index 9bc215d..d42bd54 100644
--- a/include/linux/usb/usb_qdss.h
+++ b/include/linux/usb/usb_qdss.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (c) 2012-2013, 2017-2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, 2017-2019 The Linux Foundation. All rights reserved.
*/
#ifndef __LINUX_USB_QDSS_H
@@ -17,6 +17,9 @@ struct qdss_request {
int actual;
int status;
void *context;
+ struct scatterlist *sg;
+ unsigned int num_sgs;
+ unsigned int num_mapped_sgs;
};
struct usb_qdss_ch {
diff --git a/include/linux/vmw_vmci_defs.h b/include/linux/vmw_vmci_defs.h
index b724ef7..53c5e40 100644
--- a/include/linux/vmw_vmci_defs.h
+++ b/include/linux/vmw_vmci_defs.h
@@ -68,9 +68,18 @@ enum {
/*
* A single VMCI device has an upper limit of 128MB on the amount of
- * memory that can be used for queue pairs.
+ * memory that can be used for queue pairs. Since each queue pair
+ * consists of at least two pages, the memory limit also dictates the
+ * number of queue pairs a guest can create.
*/
#define VMCI_MAX_GUEST_QP_MEMORY (128 * 1024 * 1024)
+#define VMCI_MAX_GUEST_QP_COUNT (VMCI_MAX_GUEST_QP_MEMORY / PAGE_SIZE / 2)
+
+/*
+ * There can be at most PAGE_SIZE doorbells since there is one doorbell
+ * per byte in the doorbell bitmap page.
+ */
+#define VMCI_MAX_GUEST_DOORBELL_COUNT PAGE_SIZE
/*
* Queues with pre-mapped data pages must be small, so that we don't pin
diff --git a/include/net/dst.h b/include/net/dst.h
index 6cf0870..ffc8ee0 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -313,8 +313,9 @@ static inline bool dst_hold_safe(struct dst_entry *dst)
* @skb: buffer
*
* If dst is not yet refcounted and not destroyed, grab a ref on it.
+ * Returns true if dst is refcounted.
*/
-static inline void skb_dst_force(struct sk_buff *skb)
+static inline bool skb_dst_force(struct sk_buff *skb)
{
if (skb_dst_is_noref(skb)) {
struct dst_entry *dst = skb_dst(skb);
@@ -325,6 +326,8 @@ static inline void skb_dst_force(struct sk_buff *skb)
skb->_skb_refdst = (unsigned long)dst;
}
+
+ return skb->_skb_refdst != 0UL;
}
diff --git a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h
index 236e40ba..f594eb7 100644
--- a/include/net/ip6_tunnel.h
+++ b/include/net/ip6_tunnel.h
@@ -156,9 +156,12 @@ static inline void ip6tunnel_xmit(struct sock *sk, struct sk_buff *skb,
memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
pkt_len = skb->len - skb_inner_network_offset(skb);
err = ip6_local_out(dev_net(skb_dst(skb)->dev), sk, skb);
- if (unlikely(net_xmit_eval(err)))
- pkt_len = -1;
- iptunnel_xmit_stats(dev, pkt_len);
+
+ if (dev) {
+ if (unlikely(net_xmit_eval(err)))
+ pkt_len = -1;
+ iptunnel_xmit_stats(dev, pkt_len);
+ }
}
#endif
#endif
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index a0d2e0bb..0e3c0d8 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -806,11 +806,12 @@ struct ipvs_master_sync_state {
struct ip_vs_sync_buff *sync_buff;
unsigned long sync_queue_len;
unsigned int sync_queue_delay;
- struct task_struct *master_thread;
struct delayed_work master_wakeup_work;
struct netns_ipvs *ipvs;
};
+struct ip_vs_sync_thread_data;
+
/* How much time to keep dests in trash */
#define IP_VS_DEST_TRASH_PERIOD (120 * HZ)
@@ -941,7 +942,8 @@ struct netns_ipvs {
spinlock_t sync_lock;
struct ipvs_master_sync_state *ms;
spinlock_t sync_buff_lock;
- struct task_struct **backup_threads;
+ struct ip_vs_sync_thread_data *master_tinfo;
+ struct ip_vs_sync_thread_data *backup_tinfo;
int threads_mask;
volatile int sync_state;
struct mutex sync_mutex;
diff --git a/include/net/ndisc.h b/include/net/ndisc.h
index ddfbb59..d2a016e 100644
--- a/include/net/ndisc.h
+++ b/include/net/ndisc.h
@@ -38,6 +38,7 @@ enum {
ND_OPT_RDNSS = 25, /* RFC5006 */
ND_OPT_DNSSL = 31, /* RFC6106 */
ND_OPT_6CO = 34, /* RFC6775 */
+ ND_OPT_CAPTIVE_PORTAL = 37, /* RFC7710 */
__ND_OPT_MAX
};
diff --git a/include/net/tcp.h b/include/net/tcp.h
index fe4931f..c911ecb 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1054,7 +1054,8 @@ void tcp_get_default_congestion_control(struct net *net, char *name);
void tcp_get_available_congestion_control(char *buf, size_t len);
void tcp_get_allowed_congestion_control(char *buf, size_t len);
int tcp_set_allowed_congestion_control(char *allowed);
-int tcp_set_congestion_control(struct sock *sk, const char *name, bool load, bool reinit);
+int tcp_set_congestion_control(struct sock *sk, const char *name, bool load,
+ bool reinit, bool cap_net_admin);
u32 tcp_slow_start(struct tcp_sock *tp, u32 acked);
void tcp_cong_avoid_ai(struct tcp_sock *tp, u32 w, u32 acked);
@@ -1646,6 +1647,11 @@ static inline struct sk_buff *tcp_rtx_queue_head(const struct sock *sk)
return skb_rb_first(&sk->tcp_rtx_queue);
}
+static inline struct sk_buff *tcp_rtx_queue_tail(const struct sock *sk)
+{
+ return skb_rb_last(&sk->tcp_rtx_queue);
+}
+
static inline struct sk_buff *tcp_write_queue_head(const struct sock *sk)
{
return skb_peek(&sk->sk_write_queue);
diff --git a/include/net/tls.h b/include/net/tls.h
index 9541105..98f5ad0 100644
--- a/include/net/tls.h
+++ b/include/net/tls.h
@@ -234,6 +234,7 @@ struct tls_offload_context_rx {
(ALIGN(sizeof(struct tls_offload_context_rx), sizeof(void *)) + \
TLS_DRIVER_STATE_SIZE)
+void tls_ctx_free(struct tls_context *ctx);
int wait_on_pending_writer(struct sock *sk, long *timeo);
int tls_sk_query(struct sock *sk, int optname, char __user *optval,
int __user *optlen);
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index ec299fc..412c282 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -290,8 +290,8 @@ struct ib_rss_caps {
};
enum ib_tm_cap_flags {
- /* Support tag matching on RC transport */
- IB_TM_CAP_RC = 1 << 0,
+ /* Support tag matching with rendezvous offload for RC transport */
+ IB_TM_CAP_RNDV_RC = 1 << 0,
};
struct ib_tm_caps {
diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h
index bb8092f..58507c7 100644
--- a/include/scsi/libfcoe.h
+++ b/include/scsi/libfcoe.h
@@ -241,6 +241,7 @@ struct fcoe_fcf {
* @vn_mac: VN_Node assigned MAC address for data
*/
struct fcoe_rport {
+ struct fc_rport_priv rdata;
unsigned long time;
u16 fcoe_len;
u16 flags;
diff --git a/include/soc/qcom/devfreq_devbw.h b/include/soc/qcom/devfreq_devbw.h
index 4f2643e..b4b1661 100644
--- a/include/soc/qcom/devfreq_devbw.h
+++ b/include/soc/qcom/devfreq_devbw.h
@@ -8,7 +8,7 @@
#include <linux/devfreq.h>
-#ifdef CONFIG_MSM_DEVFREQ_DEVBW
+#ifdef CONFIG_QCOM_DEVFREQ_DEVBW
int devfreq_add_devbw(struct device *dev);
int devfreq_remove_devbw(struct device *dev);
int devfreq_suspend_devbw(struct device *dev);
diff --git a/include/trace/events/android_fs.h b/include/trace/events/android_fs.h
index 4950953..0ee4a07 100644
--- a/include/trace/events/android_fs.h
+++ b/include/trace/events/android_fs.h
@@ -25,6 +25,15 @@ DEFINE_EVENT(android_fs_data_end_template, android_fs_datawrite_end,
TP_PROTO(struct inode *inode, loff_t offset, int bytes),
TP_ARGS(inode, offset, bytes));
+DEFINE_EVENT(android_fs_fsync_start_template, android_fs_fsync_start,
+ TP_PROTO(struct inode *inode,
+ pid_t pid, char *pathname, char *command),
+ TP_ARGS(inode, pid, pathname, command));
+
+DEFINE_EVENT(android_fs_data_end_template, android_fs_fsync_end,
+ TP_PROTO(struct inode *inode, loff_t offset, int bytes),
+ TP_ARGS(inode, offset, bytes));
+
#endif /* _TRACE_ANDROID_FS_H */
/* This part must be outside protection */
diff --git a/include/trace/events/android_fs_template.h b/include/trace/events/android_fs_template.h
index b23d17b..0832c26 100644
--- a/include/trace/events/android_fs_template.h
+++ b/include/trace/events/android_fs_template.h
@@ -61,4 +61,38 @@ DECLARE_EVENT_CLASS(android_fs_data_end_template,
__entry->offset, __entry->bytes)
);
+DECLARE_EVENT_CLASS(android_fs_fsync_start_template,
+ TP_PROTO(struct inode *inode,
+ pid_t pid, char *pathname, char *command),
+ TP_ARGS(inode, pid, pathname, command),
+ TP_STRUCT__entry(
+ __string(pathbuf, pathname);
+ __field(loff_t, i_size);
+ __string(cmdline, command);
+ __field(pid_t, pid);
+ __field(ino_t, ino);
+ ),
+ TP_fast_assign(
+ {
+ /*
+ * Replace the spaces in filenames and cmdlines
+ * because this screws up the tooling that parses
+ * the traces.
+ */
+ __assign_str(pathbuf, pathname);
+ (void)strreplace(__get_str(pathbuf), ' ', '_');
+ __entry->i_size = i_size_read(inode);
+ __assign_str(cmdline, command);
+ (void)strreplace(__get_str(cmdline), ' ', '_');
+ __entry->pid = pid;
+ __entry->ino = inode->i_ino;
+ }
+ ),
+ TP_printk("entry_name %s, cmdline %s,"
+ " pid %d, i_size %llu, ino %lu",
+ __get_str(pathbuf),
+ __get_str(cmdline), __entry->pid, __entry->i_size,
+ (unsigned long) __entry->ino)
+);
+
#endif /* _TRACE_ANDROID_FS_TEMPLATE_H */
diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
index 6d182746..147546e 100644
--- a/include/trace/events/rxrpc.h
+++ b/include/trace/events/rxrpc.h
@@ -1381,7 +1381,7 @@ TRACE_EVENT(rxrpc_rx_eproto,
),
TP_fast_assign(
- __entry->call = call->debug_id;
+ __entry->call = call ? call->debug_id : 0;
__entry->serial = serial;
__entry->why = why;
),
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 2932600..d143e27 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -2486,6 +2486,7 @@ struct bpf_prog_info {
char name[BPF_OBJ_NAME_LEN];
__u32 ifindex;
__u32 gpl_compatible:1;
+ __u32 :31; /* alignment pad */
__u64 netns_dev;
__u64 netns_ino;
__u32 nr_jited_ksyms;
diff --git a/include/uapi/linux/coda_psdev.h b/include/uapi/linux/coda_psdev.h
index aa6623e..d50d51a 100644
--- a/include/uapi/linux/coda_psdev.h
+++ b/include/uapi/linux/coda_psdev.h
@@ -7,19 +7,6 @@
#define CODA_PSDEV_MAJOR 67
#define MAX_CODADEVS 5 /* how many do we allow */
-
-/* messages between coda filesystem in kernel and Venus */
-struct upc_req {
- struct list_head uc_chain;
- caddr_t uc_data;
- u_short uc_flags;
- u_short uc_inSize; /* Size is at most 5000 bytes */
- u_short uc_outSize;
- u_short uc_opcode; /* copied from data to save lookup */
- int uc_unique;
- wait_queue_head_t uc_sleep; /* process' wait queue */
-};
-
#define CODA_REQ_ASYNC 0x1
#define CODA_REQ_READ 0x2
#define CODA_REQ_WRITE 0x4
diff --git a/include/uapi/linux/esoc_ctrl.h b/include/uapi/linux/esoc_ctrl.h
index 9a8a3e2..7924470 100644
--- a/include/uapi/linux/esoc_ctrl.h
+++ b/include/uapi/linux/esoc_ctrl.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
*/
#ifndef _UAPI_ESOC_CTRL_H_
#define _UAPI_ESOC_CTRL_H_
@@ -57,6 +57,7 @@ enum esoc_evt {
ESOC_CMD_ENG_OFF,
ESOC_INVALID_STATE,
ESOC_RETRY_PON_EVT,
+ ESOC_BOOT_STATE,
};
enum esoc_cmd {
diff --git a/include/uapi/linux/nilfs2_ondisk.h b/include/uapi/linux/nilfs2_ondisk.h
index a7e66ab..c23f91a 100644
--- a/include/uapi/linux/nilfs2_ondisk.h
+++ b/include/uapi/linux/nilfs2_ondisk.h
@@ -29,7 +29,7 @@
#include <linux/types.h>
#include <linux/magic.h>
-
+#include <asm/byteorder.h>
#define NILFS_INODE_BMAP_SIZE 7
@@ -533,19 +533,19 @@ enum {
static inline void \
nilfs_checkpoint_set_##name(struct nilfs_checkpoint *cp) \
{ \
- cp->cp_flags = cpu_to_le32(le32_to_cpu(cp->cp_flags) | \
- (1UL << NILFS_CHECKPOINT_##flag)); \
+ cp->cp_flags = __cpu_to_le32(__le32_to_cpu(cp->cp_flags) | \
+ (1UL << NILFS_CHECKPOINT_##flag)); \
} \
static inline void \
nilfs_checkpoint_clear_##name(struct nilfs_checkpoint *cp) \
{ \
- cp->cp_flags = cpu_to_le32(le32_to_cpu(cp->cp_flags) & \
+ cp->cp_flags = __cpu_to_le32(__le32_to_cpu(cp->cp_flags) & \
~(1UL << NILFS_CHECKPOINT_##flag)); \
} \
static inline int \
nilfs_checkpoint_##name(const struct nilfs_checkpoint *cp) \
{ \
- return !!(le32_to_cpu(cp->cp_flags) & \
+ return !!(__le32_to_cpu(cp->cp_flags) & \
(1UL << NILFS_CHECKPOINT_##flag)); \
}
@@ -595,20 +595,20 @@ enum {
static inline void \
nilfs_segment_usage_set_##name(struct nilfs_segment_usage *su) \
{ \
- su->su_flags = cpu_to_le32(le32_to_cpu(su->su_flags) | \
+ su->su_flags = __cpu_to_le32(__le32_to_cpu(su->su_flags) | \
(1UL << NILFS_SEGMENT_USAGE_##flag));\
} \
static inline void \
nilfs_segment_usage_clear_##name(struct nilfs_segment_usage *su) \
{ \
su->su_flags = \
- cpu_to_le32(le32_to_cpu(su->su_flags) & \
+ __cpu_to_le32(__le32_to_cpu(su->su_flags) & \
~(1UL << NILFS_SEGMENT_USAGE_##flag)); \
} \
static inline int \
nilfs_segment_usage_##name(const struct nilfs_segment_usage *su) \
{ \
- return !!(le32_to_cpu(su->su_flags) & \
+ return !!(__le32_to_cpu(su->su_flags) & \
(1UL << NILFS_SEGMENT_USAGE_##flag)); \
}
@@ -619,15 +619,15 @@ NILFS_SEGMENT_USAGE_FNS(ERROR, error)
static inline void
nilfs_segment_usage_set_clean(struct nilfs_segment_usage *su)
{
- su->su_lastmod = cpu_to_le64(0);
- su->su_nblocks = cpu_to_le32(0);
- su->su_flags = cpu_to_le32(0);
+ su->su_lastmod = __cpu_to_le64(0);
+ su->su_nblocks = __cpu_to_le32(0);
+ su->su_flags = __cpu_to_le32(0);
}
static inline int
nilfs_segment_usage_clean(const struct nilfs_segment_usage *su)
{
- return !le32_to_cpu(su->su_flags);
+ return !__le32_to_cpu(su->su_flags);
}
/**
diff --git a/include/uapi/linux/usb/audio.h b/include/uapi/linux/usb/audio.h
index ddc5396..76b7c3f 100644
--- a/include/uapi/linux/usb/audio.h
+++ b/include/uapi/linux/usb/audio.h
@@ -450,6 +450,43 @@ static inline __u8 *uac_processing_unit_specific(struct uac_processing_unit_desc
}
}
+/*
+ * Extension Unit (XU) has almost compatible layout with Processing Unit, but
+ * on UAC2, it has a different bmControls size (bControlSize); it's 1 byte for
+ * XU while 2 bytes for PU. The last iExtension field is a one-byte index as
+ * well as iProcessing field of PU.
+ */
+static inline __u8 uac_extension_unit_bControlSize(struct uac_processing_unit_descriptor *desc,
+ int protocol)
+{
+ switch (protocol) {
+ case UAC_VERSION_1:
+ return desc->baSourceID[desc->bNrInPins + 4];
+ case UAC_VERSION_2:
+ return 1; /* in UAC2, this value is constant */
+ case UAC_VERSION_3:
+ return 4; /* in UAC3, this value is constant */
+ default:
+ return 1;
+ }
+}
+
+static inline __u8 uac_extension_unit_iExtension(struct uac_processing_unit_descriptor *desc,
+ int protocol)
+{
+ __u8 control_size = uac_extension_unit_bControlSize(desc, protocol);
+
+ switch (protocol) {
+ case UAC_VERSION_1:
+ case UAC_VERSION_2:
+ default:
+ return *(uac_processing_unit_bmControls(desc, protocol)
+ + control_size);
+ case UAC_VERSION_3:
+ return 0; /* UAC3 does not have this field */
+ }
+}
+
/* 4.5.2 Class-Specific AS Interface Descriptor */
struct uac1_as_header_descriptor {
__u8 bLength; /* in bytes: 7 */
diff --git a/include/uapi/media/msm_vidc_utils.h b/include/uapi/media/msm_vidc_utils.h
index 14ee584..18fdddb 100644
--- a/include/uapi/media/msm_vidc_utils.h
+++ b/include/uapi/media/msm_vidc_utils.h
@@ -348,4 +348,25 @@ enum msm_vidc_hdr_info_types {
MSM_VIDC_RGB_MAX_FLL,
};
+enum msm_vidc_plane_reserved_field_types {
+ MSM_VIDC_BUFFER_FD,
+ MSM_VIDC_DATA_OFFSET,
+ MSM_VIDC_COMP_RATIO,
+ MSM_VIDC_INPUT_TAG_1,
+ MSM_VIDC_INPUT_TAG_2,
+};
+
+enum msm_vidc_cb_event_types {
+ MSM_VIDC_HEIGHT,
+ MSM_VIDC_WIDTH,
+ MSM_VIDC_BIT_DEPTH,
+ MSM_VIDC_PIC_STRUCT,
+ MSM_VIDC_COLOR_SPACE,
+ MSM_VIDC_CROP_TOP,
+ MSM_VIDC_CROP_LEFT,
+ MSM_VIDC_CROP_HEIGHT,
+ MSM_VIDC_CROP_WIDTH,
+ MSM_VIDC_PROFILE,
+ MSM_VIDC_LEVEL,
+};
#endif
diff --git a/include/xen/events.h b/include/xen/events.h
index c3e6bc6..1650d39 100644
--- a/include/xen/events.h
+++ b/include/xen/events.h
@@ -3,6 +3,7 @@
#define _XEN_EVENTS_H
#include <linux/interrupt.h>
+#include <linux/irq.h>
#ifdef CONFIG_PCI_MSI
#include <linux/msi.h>
#endif
@@ -59,7 +60,7 @@ void evtchn_put(unsigned int evtchn);
void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector);
void rebind_evtchn_irq(int evtchn, int irq);
-int xen_rebind_evtchn_to_cpu(int evtchn, unsigned tcpu);
+int xen_set_affinity_evtchn(struct irq_desc *desc, unsigned int tcpu);
static inline void notify_remote_via_evtchn(int port)
{
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 94bc9584..8763ee7 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -389,7 +389,6 @@ static void mqueue_evict_inode(struct inode *inode)
{
struct mqueue_inode_info *info;
struct user_struct *user;
- unsigned long mq_bytes, mq_treesize;
struct ipc_namespace *ipc_ns;
struct msg_msg *msg, *nmsg;
LIST_HEAD(tmp_msg);
@@ -412,16 +411,18 @@ static void mqueue_evict_inode(struct inode *inode)
free_msg(msg);
}
- /* Total amount of bytes accounted for the mqueue */
- mq_treesize = info->attr.mq_maxmsg * sizeof(struct msg_msg) +
- min_t(unsigned int, info->attr.mq_maxmsg, MQ_PRIO_MAX) *
- sizeof(struct posix_msg_tree_node);
-
- mq_bytes = mq_treesize + (info->attr.mq_maxmsg *
- info->attr.mq_msgsize);
-
user = info->user;
if (user) {
+ unsigned long mq_bytes, mq_treesize;
+
+ /* Total amount of bytes accounted for the mqueue */
+ mq_treesize = info->attr.mq_maxmsg * sizeof(struct msg_msg) +
+ min_t(unsigned int, info->attr.mq_maxmsg, MQ_PRIO_MAX) *
+ sizeof(struct posix_msg_tree_node);
+
+ mq_bytes = mq_treesize + (info->attr.mq_maxmsg *
+ info->attr.mq_msgsize);
+
spin_lock(&mq_lock);
user->mq_bytes -= mq_bytes;
/*
diff --git a/kernel/Makefile b/kernel/Makefile
index 33dfa00..c2aa5bd 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -32,8 +32,13 @@
KASAN_SANITIZE_kcov.o := n
CFLAGS_kcov.o := $(call cc-option, -fno-conserve-stack -fno-stack-protector)
-# cond_syscall is currently not LTO compatible
+ifndef CONFIG_CFI_CLANG
+# cond_syscall is currently not gcc LTO compatible
CFLAGS_sys_ni.o = $(DISABLE_LTO)
+endif
+
+# Don't instrument error handlers
+CFLAGS_cfi.o = $(DISABLE_CFI_CLANG)
# Don't instrument error handlers
CFLAGS_cfi.o = $(DISABLE_CFI_CLANG)
diff --git a/kernel/bpf/Makefile b/kernel/bpf/Makefile
index 0488b82..ffc39a7 100644
--- a/kernel/bpf/Makefile
+++ b/kernel/bpf/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
obj-y := core.o
+CFLAGS_core.o += $(call cc-disable-warning, override-init)
obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o tnum.o
obj-$(CONFIG_BPF_SYSCALL) += hashtab.o arraymap.o percpu_freelist.o bpf_lru_list.o lpm_trie.o map_in_map.o
diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c
index 2faad03..fc500ca 100644
--- a/kernel/bpf/devmap.c
+++ b/kernel/bpf/devmap.c
@@ -186,6 +186,7 @@ static void dev_map_free(struct bpf_map *map)
if (!dev)
continue;
+ free_percpu(dev->bulkq);
dev_put(dev->dev);
kfree(dev);
}
@@ -281,6 +282,7 @@ void __dev_map_flush(struct bpf_map *map)
unsigned long *bitmap = this_cpu_ptr(dtab->flush_needed);
u32 bit;
+ rcu_read_lock();
for_each_set_bit(bit, bitmap, map->max_entries) {
struct bpf_dtab_netdev *dev = READ_ONCE(dtab->netdev_map[bit]);
struct xdp_bulk_queue *bq;
@@ -291,11 +293,12 @@ void __dev_map_flush(struct bpf_map *map)
if (unlikely(!dev))
continue;
- __clear_bit(bit, bitmap);
-
bq = this_cpu_ptr(dev->bulkq);
bq_xmit_all(dev, bq, XDP_XMIT_FLUSH, true);
+
+ __clear_bit(bit, bitmap);
}
+ rcu_read_unlock();
}
/* rcu_read_lock (from syscall and BPF contexts) ensures that if a delete and/or
@@ -388,6 +391,7 @@ static void dev_map_flush_old(struct bpf_dtab_netdev *dev)
int cpu;
+ rcu_read_lock();
for_each_online_cpu(cpu) {
bitmap = per_cpu_ptr(dev->dtab->flush_needed, cpu);
__clear_bit(dev->bit, bitmap);
@@ -395,6 +399,7 @@ static void dev_map_flush_old(struct bpf_dtab_netdev *dev)
bq = per_cpu_ptr(dev->bulkq, cpu);
bq_xmit_all(dev, bq, XDP_XMIT_FLUSH, false);
}
+ rcu_read_unlock();
}
}
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 9a66ad3..8e91dd0 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -213,7 +213,8 @@ static struct cftype cgroup_base_files[];
static int cgroup_apply_control(struct cgroup *cgrp);
static void cgroup_finalize_control(struct cgroup *cgrp, int ret);
-static void css_task_iter_advance(struct css_task_iter *it);
+static void css_task_iter_skip(struct css_task_iter *it,
+ struct task_struct *task);
static int cgroup_destroy_locked(struct cgroup *cgrp);
static struct cgroup_subsys_state *css_create(struct cgroup *cgrp,
struct cgroup_subsys *ss);
@@ -673,6 +674,7 @@ struct css_set init_css_set = {
.dom_cset = &init_css_set,
.tasks = LIST_HEAD_INIT(init_css_set.tasks),
.mg_tasks = LIST_HEAD_INIT(init_css_set.mg_tasks),
+ .dying_tasks = LIST_HEAD_INIT(init_css_set.dying_tasks),
.task_iters = LIST_HEAD_INIT(init_css_set.task_iters),
.threaded_csets = LIST_HEAD_INIT(init_css_set.threaded_csets),
.cgrp_links = LIST_HEAD_INIT(init_css_set.cgrp_links),
@@ -776,6 +778,21 @@ static void css_set_update_populated(struct css_set *cset, bool populated)
cgroup_update_populated(link->cgrp, populated);
}
+/*
+ * @task is leaving, advance task iterators which are pointing to it so
+ * that they can resume at the next position. Advancing an iterator might
+ * remove it from the list, use safe walk. See css_task_iter_skip() for
+ * details.
+ */
+static void css_set_skip_task_iters(struct css_set *cset,
+ struct task_struct *task)
+{
+ struct css_task_iter *it, *pos;
+
+ list_for_each_entry_safe(it, pos, &cset->task_iters, iters_node)
+ css_task_iter_skip(it, task);
+}
+
/**
* css_set_move_task - move a task from one css_set to another
* @task: task being moved
@@ -801,22 +818,9 @@ static void css_set_move_task(struct task_struct *task,
css_set_update_populated(to_cset, true);
if (from_cset) {
- struct css_task_iter *it, *pos;
-
WARN_ON_ONCE(list_empty(&task->cg_list));
- /*
- * @task is leaving, advance task iterators which are
- * pointing to it so that they can resume at the next
- * position. Advancing an iterator might remove it from
- * the list, use safe walk. See css_task_iter_advance*()
- * for details.
- */
- list_for_each_entry_safe(it, pos, &from_cset->task_iters,
- iters_node)
- if (it->task_pos == &task->cg_list)
- css_task_iter_advance(it);
-
+ css_set_skip_task_iters(from_cset, task);
list_del_init(&task->cg_list);
if (!css_set_populated(from_cset))
css_set_update_populated(from_cset, false);
@@ -1143,6 +1147,7 @@ static struct css_set *find_css_set(struct css_set *old_cset,
cset->dom_cset = cset;
INIT_LIST_HEAD(&cset->tasks);
INIT_LIST_HEAD(&cset->mg_tasks);
+ INIT_LIST_HEAD(&cset->dying_tasks);
INIT_LIST_HEAD(&cset->task_iters);
INIT_LIST_HEAD(&cset->threaded_csets);
INIT_HLIST_NODE(&cset->hlist);
@@ -4235,15 +4240,18 @@ static void css_task_iter_advance_css_set(struct css_task_iter *it)
it->task_pos = NULL;
return;
}
- } while (!css_set_populated(cset));
+ } while (!css_set_populated(cset) && list_empty(&cset->dying_tasks));
if (!list_empty(&cset->tasks))
it->task_pos = cset->tasks.next;
- else
+ else if (!list_empty(&cset->mg_tasks))
it->task_pos = cset->mg_tasks.next;
+ else
+ it->task_pos = cset->dying_tasks.next;
it->tasks_head = &cset->tasks;
it->mg_tasks_head = &cset->mg_tasks;
+ it->dying_tasks_head = &cset->dying_tasks;
/*
* We don't keep css_sets locked across iteration steps and thus
@@ -4269,9 +4277,20 @@ static void css_task_iter_advance_css_set(struct css_task_iter *it)
list_add(&it->iters_node, &cset->task_iters);
}
+static void css_task_iter_skip(struct css_task_iter *it,
+ struct task_struct *task)
+{
+ lockdep_assert_held(&css_set_lock);
+
+ if (it->task_pos == &task->cg_list) {
+ it->task_pos = it->task_pos->next;
+ it->flags |= CSS_TASK_ITER_SKIPPED;
+ }
+}
+
static void css_task_iter_advance(struct css_task_iter *it)
{
- struct list_head *next;
+ struct task_struct *task;
lockdep_assert_held(&css_set_lock);
repeat:
@@ -4281,25 +4300,40 @@ static void css_task_iter_advance(struct css_task_iter *it)
* consumed first and then ->mg_tasks. After ->mg_tasks,
* we move onto the next cset.
*/
- next = it->task_pos->next;
-
- if (next == it->tasks_head)
- next = it->mg_tasks_head->next;
-
- if (next == it->mg_tasks_head)
- css_task_iter_advance_css_set(it);
+ if (it->flags & CSS_TASK_ITER_SKIPPED)
+ it->flags &= ~CSS_TASK_ITER_SKIPPED;
else
- it->task_pos = next;
+ it->task_pos = it->task_pos->next;
+
+ if (it->task_pos == it->tasks_head)
+ it->task_pos = it->mg_tasks_head->next;
+ if (it->task_pos == it->mg_tasks_head)
+ it->task_pos = it->dying_tasks_head->next;
+ if (it->task_pos == it->dying_tasks_head)
+ css_task_iter_advance_css_set(it);
} else {
/* called from start, proceed to the first cset */
css_task_iter_advance_css_set(it);
}
- /* if PROCS, skip over tasks which aren't group leaders */
- if ((it->flags & CSS_TASK_ITER_PROCS) && it->task_pos &&
- !thread_group_leader(list_entry(it->task_pos, struct task_struct,
- cg_list)))
- goto repeat;
+ if (!it->task_pos)
+ return;
+
+ task = list_entry(it->task_pos, struct task_struct, cg_list);
+
+ if (it->flags & CSS_TASK_ITER_PROCS) {
+ /* if PROCS, skip over tasks which aren't group leaders */
+ if (!thread_group_leader(task))
+ goto repeat;
+
+ /* and dying leaders w/o live member threads */
+ if (!atomic_read(&task->signal->live))
+ goto repeat;
+ } else {
+ /* skip all dying ones */
+ if (task->flags & PF_EXITING)
+ goto repeat;
+ }
}
/**
@@ -4355,6 +4389,10 @@ struct task_struct *css_task_iter_next(struct css_task_iter *it)
spin_lock_irq(&css_set_lock);
+ /* @it may be half-advanced by skips, finish advancing */
+ if (it->flags & CSS_TASK_ITER_SKIPPED)
+ css_task_iter_advance(it);
+
if (it->task_pos) {
it->cur_task = list_entry(it->task_pos, struct task_struct,
cg_list);
@@ -5790,6 +5828,7 @@ void cgroup_exit(struct task_struct *tsk)
if (!list_empty(&tsk->cg_list)) {
spin_lock_irq(&css_set_lock);
css_set_move_task(tsk, cset, NULL, false);
+ list_add_tail(&tsk->cg_list, &cset->dying_tasks);
cset->nr_tasks--;
spin_unlock_irq(&css_set_lock);
} else {
@@ -5810,6 +5849,13 @@ void cgroup_release(struct task_struct *task)
do_each_subsys_mask(ss, ssid, have_release_callback) {
ss->release(task);
} while_each_subsys_mask();
+
+ if (use_task_css_set_links) {
+ spin_lock_irq(&css_set_lock);
+ css_set_skip_task_iters(task_css_set(task), task);
+ list_del_init(&task->cg_list);
+ spin_unlock_irq(&css_set_lock);
+ }
}
void cgroup_free(struct task_struct *task)
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 1e7b25c..a040bf9 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -2008,6 +2008,9 @@ static ssize_t write_cpuhp_fail(struct device *dev,
if (ret)
return ret;
+ if (fail < CPUHP_OFFLINE || fail > CPUHP_ONLINE)
+ return -EINVAL;
+
/*
* Cannot fail STARTING/DYING callbacks.
*/
diff --git a/kernel/cred.c b/kernel/cred.c
index efd04b2..5ab1f7e 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -147,7 +147,10 @@ void __put_cred(struct cred *cred)
BUG_ON(cred == current->cred);
BUG_ON(cred == current->real_cred);
- call_rcu(&cred->rcu, put_cred_rcu);
+ if (cred->non_rcu)
+ put_cred_rcu(&cred->rcu);
+ else
+ call_rcu(&cred->rcu, put_cred_rcu);
}
EXPORT_SYMBOL(__put_cred);
@@ -258,6 +261,7 @@ struct cred *prepare_creds(void)
old = task->cred;
memcpy(new, old, sizeof(struct cred));
+ new->non_rcu = 0;
atomic_set(&new->usage, 1);
set_cred_subscribers(new, 0);
get_group_info(new->group_info);
@@ -537,7 +541,19 @@ const struct cred *override_creds(const struct cred *new)
validate_creds(old);
validate_creds(new);
- get_cred(new);
+
+ /*
+ * NOTE! This uses 'get_new_cred()' rather than 'get_cred()'.
+ *
+ * That means that we do not clear the 'non_rcu' flag, since
+ * we are only installing the cred into the thread-synchronous
+ * '->cred' pointer, not the '->real_cred' pointer that is
+ * visible to other threads under RCU.
+ *
+ * Also note that we did validate_creds() manually, not depending
+ * on the validation in 'get_cred()'.
+ */
+ get_new_cred((struct cred *)new);
alter_cred_subscribers(new, 1);
rcu_assign_pointer(current->cred, new);
alter_cred_subscribers(old, -1);
@@ -620,6 +636,7 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon)
validate_creds(old);
*new = *old;
+ new->non_rcu = 0;
atomic_set(&new->usage, 1);
set_cred_subscribers(new, 0);
get_uid(new->user);
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 9e13143..888d93c 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -2595,6 +2595,9 @@ static int __perf_install_in_context(void *info)
return ret;
}
+static bool exclusive_event_installable(struct perf_event *event,
+ struct perf_event_context *ctx);
+
/*
* Attach a performance event to a context.
*
@@ -2609,6 +2612,8 @@ perf_install_in_context(struct perf_event_context *ctx,
lockdep_assert_held(&ctx->mutex);
+ WARN_ON_ONCE(!exclusive_event_installable(event, ctx));
+
if (event->cpu != -1)
event->cpu = cpu;
@@ -4445,7 +4450,7 @@ static int exclusive_event_init(struct perf_event *event)
{
struct pmu *pmu = event->pmu;
- if (!(pmu->capabilities & PERF_PMU_CAP_EXCLUSIVE))
+ if (!is_exclusive_pmu(pmu))
return 0;
/*
@@ -4476,7 +4481,7 @@ static void exclusive_event_destroy(struct perf_event *event)
{
struct pmu *pmu = event->pmu;
- if (!(pmu->capabilities & PERF_PMU_CAP_EXCLUSIVE))
+ if (!is_exclusive_pmu(pmu))
return;
/* see comment in exclusive_event_init() */
@@ -4496,14 +4501,15 @@ static bool exclusive_event_match(struct perf_event *e1, struct perf_event *e2)
return false;
}
-/* Called under the same ctx::mutex as perf_install_in_context() */
static bool exclusive_event_installable(struct perf_event *event,
struct perf_event_context *ctx)
{
struct perf_event *iter_event;
struct pmu *pmu = event->pmu;
- if (!(pmu->capabilities & PERF_PMU_CAP_EXCLUSIVE))
+ lockdep_assert_held(&ctx->mutex);
+
+ if (!is_exclusive_pmu(pmu))
return true;
list_for_each_entry(iter_event, &ctx->event_list, event_entry) {
@@ -4579,12 +4585,20 @@ static void _free_event(struct perf_event *event)
if (event->destroy)
event->destroy(event);
- if (event->ctx)
- put_ctx(event->ctx);
-
+ /*
+ * Must be after ->destroy(), due to uprobe_perf_close() using
+ * hw.target.
+ */
if (event->hw.target)
put_task_struct(event->hw.target);
+ /*
+ * perf_event_free_task() relies on put_ctx() being 'last', in particular
+ * all task references must be cleaned up.
+ */
+ if (event->ctx)
+ put_ctx(event->ctx);
+
exclusive_event_destroy(event);
module_put(event->pmu->module);
@@ -4784,8 +4798,17 @@ static int __perf_event_release_kernel(struct perf_event *event)
mutex_unlock(&event->child_mutex);
list_for_each_entry_safe(child, tmp, &free_list, child_list) {
+ void *var = &child->ctx->refcount;
+
list_del(&child->child_list);
free_event(child);
+
+ /*
+ * Wake any perf_event_free_task() waiting for this event to be
+ * freed.
+ */
+ smp_mb(); /* pairs with wait_var_event() */
+ wake_up_var(var);
}
no_ctx:
@@ -6079,7 +6102,7 @@ static void perf_sample_regs_user(struct perf_regs *regs_user,
if (user_mode(regs)) {
regs_user->abi = perf_reg_abi(current);
regs_user->regs = regs;
- } else if (current->mm) {
+ } else if (!(current->flags & PF_KTHREAD)) {
perf_get_regs_user(regs_user, regs, regs_user_copy);
} else {
regs_user->abi = PERF_SAMPLE_REGS_ABI_NONE;
@@ -10952,11 +10975,6 @@ SYSCALL_DEFINE5(perf_event_open,
goto err_alloc;
}
- if ((pmu->capabilities & PERF_PMU_CAP_EXCLUSIVE) && group_leader) {
- err = -EBUSY;
- goto err_context;
- }
-
/*
* Look up the group leader (we will attach this event to it):
*/
@@ -11044,6 +11062,18 @@ SYSCALL_DEFINE5(perf_event_open,
move_group = 0;
}
}
+
+ /*
+ * Failure to create exclusive events returns -EBUSY.
+ */
+ err = -EBUSY;
+ if (!exclusive_event_installable(group_leader, ctx))
+ goto err_locked;
+
+ for_each_sibling_event(sibling, group_leader) {
+ if (!exclusive_event_installable(sibling, ctx))
+ goto err_locked;
+ }
} else {
mutex_lock(&ctx->mutex);
}
@@ -11063,9 +11093,6 @@ SYSCALL_DEFINE5(perf_event_open,
* because we need to serialize with concurrent event creation.
*/
if (!event->shared && !exclusive_event_installable(event, ctx)) {
- /* exclusive and group stuff are assumed mutually exclusive */
- WARN_ON_ONCE(move_group);
-
err = -EBUSY;
goto err_locked;
}
@@ -11550,11 +11577,11 @@ static void perf_free_event(struct perf_event *event,
}
/*
- * Free an unexposed, unused context as created by inheritance by
- * perf_event_init_task below, used by fork() in case of fail.
+ * Free a context as created by inheritance by perf_event_init_task() below,
+ * used by fork() in case of fail.
*
- * Not all locks are strictly required, but take them anyway to be nice and
- * help out with the lockdep assertions.
+ * Even though the task has never lived, the context and events have been
+ * exposed through the child_list, so we must take care tearing it all down.
*/
void perf_event_free_task(struct task_struct *task)
{
@@ -11584,7 +11611,23 @@ void perf_event_free_task(struct task_struct *task)
perf_free_event(event, ctx);
mutex_unlock(&ctx->mutex);
- put_ctx(ctx);
+
+ /*
+ * perf_event_release_kernel() could've stolen some of our
+ * child events and still have them on its free_list. In that
+ * case we must wait for these events to have been freed (in
+ * particular all their references to this task must've been
+ * dropped).
+ *
+ * Without this copy_process() will unconditionally free this
+ * task (irrespective of its reference count) and
+ * _free_event()'s put_task_struct(event->hw.target) will be a
+ * use-after-free.
+ *
+ * Wait for all events to drop their context reference.
+ */
+ wait_var_event(&ctx->refcount, atomic_read(&ctx->refcount) == 1);
+ put_ctx(ctx); /* must be last */
}
}
diff --git a/kernel/exit.c b/kernel/exit.c
index 942f0a5..aae5cc5 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -194,6 +194,7 @@ void release_task(struct task_struct *p)
rcu_read_unlock();
proc_flush_task(p);
+ cgroup_release(p);
write_lock_irq(&tasklist_lock);
ptrace_release_task(p);
@@ -219,7 +220,6 @@ void release_task(struct task_struct *p)
}
write_unlock_irq(&tasklist_lock);
- cgroup_release(p);
release_thread(p);
call_rcu(&p->rcu, delayed_put_task_struct);
diff --git a/kernel/fork.c b/kernel/fork.c
index e7a644e..6a5d06d 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -714,7 +714,7 @@ void __put_task_struct(struct task_struct *tsk)
WARN_ON(tsk == current);
cgroup_free(tsk);
- task_numa_free(tsk);
+ task_numa_free(tsk, true);
security_task_free(tsk);
exit_creds(tsk);
delayacct_tsk_free(tsk);
diff --git a/kernel/irq/autoprobe.c b/kernel/irq/autoprobe.c
index 16cbf6b..ae60cae 100644
--- a/kernel/irq/autoprobe.c
+++ b/kernel/irq/autoprobe.c
@@ -90,7 +90,7 @@ unsigned long probe_irq_on(void)
/* It triggered already - consider it spurious. */
if (!(desc->istate & IRQS_WAITING)) {
desc->istate &= ~IRQS_AUTODETECT;
- irq_shutdown(desc);
+ irq_shutdown_and_deactivate(desc);
} else
if (i < 32)
mask |= 1 << i;
@@ -127,7 +127,7 @@ unsigned int probe_irq_mask(unsigned long val)
mask |= 1 << i;
desc->istate &= ~IRQS_AUTODETECT;
- irq_shutdown(desc);
+ irq_shutdown_and_deactivate(desc);
}
raw_spin_unlock_irq(&desc->lock);
}
@@ -169,7 +169,7 @@ int probe_irq_off(unsigned long val)
nr_of_irqs++;
}
desc->istate &= ~IRQS_AUTODETECT;
- irq_shutdown(desc);
+ irq_shutdown_and_deactivate(desc);
}
raw_spin_unlock_irq(&desc->lock);
}
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 6e34459..068fc01 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -314,6 +314,12 @@ void irq_shutdown(struct irq_desc *desc)
}
irq_state_clr_started(desc);
}
+}
+
+
+void irq_shutdown_and_deactivate(struct irq_desc *desc)
+{
+ irq_shutdown(desc);
/*
* This must be called even if the interrupt was never started up,
* because the activation can happen before the interrupt is
diff --git a/kernel/irq/cpuhotplug.c b/kernel/irq/cpuhotplug.c
index 6bf30b2..b19a659 100644
--- a/kernel/irq/cpuhotplug.c
+++ b/kernel/irq/cpuhotplug.c
@@ -124,7 +124,7 @@ static bool migrate_one_irq(struct irq_desc *desc)
*/
if (irqd_affinity_is_managed(d)) {
irqd_set_managed_shutdown(d);
- irq_shutdown(desc);
+ irq_shutdown_and_deactivate(desc);
return false;
}
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
index e74e7ee..ea57f3d 100644
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -80,6 +80,7 @@ extern int irq_activate_and_startup(struct irq_desc *desc, bool resend);
extern int irq_startup(struct irq_desc *desc, bool resend, bool force);
extern void irq_shutdown(struct irq_desc *desc);
+extern void irq_shutdown_and_deactivate(struct irq_desc *desc);
extern void irq_enable(struct irq_desc *desc);
extern void irq_disable(struct irq_desc *desc);
extern void irq_percpu_enable(struct irq_desc *desc, unsigned int cpu);
@@ -94,6 +95,10 @@ static inline void irq_mark_irq(unsigned int irq) { }
extern void irq_mark_irq(unsigned int irq);
#endif
+extern int __irq_get_irqchip_state(struct irq_data *data,
+ enum irqchip_irq_state which,
+ bool *state);
+
extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr);
irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags);
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index cd4f9f3..23bcfa7 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/random.h>
#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/sched/rt.h>
@@ -34,8 +35,9 @@ static int __init setup_forced_irqthreads(char *arg)
early_param("threadirqs", setup_forced_irqthreads);
#endif
-static void __synchronize_hardirq(struct irq_desc *desc)
+static void __synchronize_hardirq(struct irq_desc *desc, bool sync_chip)
{
+ struct irq_data *irqd = irq_desc_get_irq_data(desc);
bool inprogress;
do {
@@ -51,6 +53,20 @@ static void __synchronize_hardirq(struct irq_desc *desc)
/* Ok, that indicated we're done: double-check carefully. */
raw_spin_lock_irqsave(&desc->lock, flags);
inprogress = irqd_irq_inprogress(&desc->irq_data);
+
+ /*
+ * If requested and supported, check at the chip whether it
+ * is in flight at the hardware level, i.e. already pending
+ * in a CPU and waiting for service and acknowledge.
+ */
+ if (!inprogress && sync_chip) {
+ /*
+ * Ignore the return code. inprogress is only updated
+ * when the chip supports it.
+ */
+ __irq_get_irqchip_state(irqd, IRQCHIP_STATE_ACTIVE,
+ &inprogress);
+ }
raw_spin_unlock_irqrestore(&desc->lock, flags);
/* Oops, that failed? */
@@ -73,13 +89,18 @@ static void __synchronize_hardirq(struct irq_desc *desc)
* Returns: false if a threaded handler is active.
*
* This function may be called - with care - from IRQ context.
+ *
+ * It does not check whether there is an interrupt in flight at the
+ * hardware level, but not serviced yet, as this might deadlock when
+ * called with interrupts disabled and the target CPU of the interrupt
+ * is the current CPU.
*/
bool synchronize_hardirq(unsigned int irq)
{
struct irq_desc *desc = irq_to_desc(irq);
if (desc) {
- __synchronize_hardirq(desc);
+ __synchronize_hardirq(desc, false);
return !atomic_read(&desc->threads_active);
}
@@ -95,14 +116,19 @@ EXPORT_SYMBOL(synchronize_hardirq);
* to complete before returning. If you use this function while
* holding a resource the IRQ handler may need you will deadlock.
*
- * This function may be called - with care - from IRQ context.
+ * Can only be called from preemptible code as it might sleep when
+ * an interrupt thread is associated to @irq.
+ *
+ * It optionally makes sure (when the irq chip supports that method)
+ * that the interrupt is not pending in any CPU and waiting for
+ * service.
*/
void synchronize_irq(unsigned int irq)
{
struct irq_desc *desc = irq_to_desc(irq);
if (desc) {
- __synchronize_hardirq(desc);
+ __synchronize_hardirq(desc, true);
/*
* We made sure that no hardirq handler is
* running. Now verify that no threaded handlers are
@@ -1619,6 +1645,7 @@ static struct irqaction *__free_irq(struct irq_desc *desc, void *dev_id)
/* If this was the last handler, shut down the IRQ line: */
if (!desc->action) {
irq_settings_clr_disable_unlazy(desc);
+ /* Only shutdown. Deactivate after synchronize_hardirq() */
irq_shutdown(desc);
}
@@ -1647,8 +1674,12 @@ static struct irqaction *__free_irq(struct irq_desc *desc, void *dev_id)
unregister_handler_proc(irq, action);
- /* Make sure it's not being used on another CPU: */
- synchronize_hardirq(irq);
+ /*
+ * Make sure it's not being used on another CPU and if the chip
+ * supports it also make sure that there is no (not yet serviced)
+ * interrupt in flight at the hardware level.
+ */
+ __synchronize_hardirq(desc, true);
#ifdef CONFIG_DEBUG_SHIRQ
/*
@@ -1688,6 +1719,14 @@ static struct irqaction *__free_irq(struct irq_desc *desc, void *dev_id)
* require it to deallocate resources over the slow bus.
*/
chip_bus_lock(desc);
+ /*
+ * There is no interrupt on the fly anymore. Deactivate it
+ * completely.
+ */
+ raw_spin_lock_irqsave(&desc->lock, flags);
+ irq_domain_deactivate_irq(&desc->irq_data);
+ raw_spin_unlock_irqrestore(&desc->lock, flags);
+
irq_release_resources(desc);
chip_bus_sync_unlock(desc);
irq_remove_timings(desc);
@@ -2173,6 +2212,28 @@ int __request_percpu_irq(unsigned int irq, irq_handler_t handler,
}
EXPORT_SYMBOL_GPL(__request_percpu_irq);
+int __irq_get_irqchip_state(struct irq_data *data, enum irqchip_irq_state which,
+ bool *state)
+{
+ struct irq_chip *chip;
+ int err = -EINVAL;
+
+ do {
+ chip = irq_data_get_irq_chip(data);
+ if (chip->irq_get_irqchip_state)
+ break;
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+ data = data->parent_data;
+#else
+ data = NULL;
+#endif
+ } while (data);
+
+ if (data)
+ err = chip->irq_get_irqchip_state(data, which, state);
+ return err;
+}
+
/**
* irq_get_irqchip_state - returns the irqchip state of a interrupt.
* @irq: Interrupt line that is forwarded to a VM
@@ -2191,7 +2252,6 @@ int irq_get_irqchip_state(unsigned int irq, enum irqchip_irq_state which,
{
struct irq_desc *desc;
struct irq_data *data;
- struct irq_chip *chip;
unsigned long flags;
int err = -EINVAL;
@@ -2201,19 +2261,7 @@ int irq_get_irqchip_state(unsigned int irq, enum irqchip_irq_state which,
data = irq_desc_get_irq_data(desc);
- do {
- chip = irq_data_get_irq_chip(data);
- if (chip->irq_get_irqchip_state)
- break;
-#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
- data = data->parent_data;
-#else
- data = NULL;
-#endif
- } while (data);
-
- if (data)
- err = chip->irq_get_irqchip_state(data, which, state);
+ err = __irq_get_irqchip_state(data, which, state);
irq_put_desc_busunlock(desc, flags);
return err;
diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
index 26b57e2..e810e8c 100644
--- a/kernel/locking/lockdep.c
+++ b/kernel/locking/lockdep.c
@@ -3326,17 +3326,17 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
if (depth) {
hlock = curr->held_locks + depth - 1;
if (hlock->class_idx == class_idx && nest_lock) {
- if (hlock->references) {
- /*
- * Check: unsigned int references:12, overflow.
- */
- if (DEBUG_LOCKS_WARN_ON(hlock->references == (1 << 12)-1))
- return 0;
+ if (!references)
+ references++;
+ if (!hlock->references)
hlock->references++;
- } else {
- hlock->references = 2;
- }
+
+ hlock->references += references;
+
+ /* Overflow */
+ if (DEBUG_LOCKS_WARN_ON(hlock->references < references))
+ return 0;
return 1;
}
diff --git a/kernel/locking/lockdep_proc.c b/kernel/locking/lockdep_proc.c
index 3dd980d..6fcc465 100644
--- a/kernel/locking/lockdep_proc.c
+++ b/kernel/locking/lockdep_proc.c
@@ -200,7 +200,6 @@ static void lockdep_stats_debug_show(struct seq_file *m)
static int lockdep_stats_show(struct seq_file *m, void *v)
{
- struct lock_class *class;
unsigned long nr_unused = 0, nr_uncategorized = 0,
nr_irq_safe = 0, nr_irq_unsafe = 0,
nr_softirq_safe = 0, nr_softirq_unsafe = 0,
@@ -210,6 +209,9 @@ static int lockdep_stats_show(struct seq_file *m, void *v)
nr_hardirq_read_safe = 0, nr_hardirq_read_unsafe = 0,
sum_forward_deps = 0;
+#ifdef CONFIG_PROVE_LOCKING
+ struct lock_class *class;
+
list_for_each_entry(class, &all_lock_classes, lock_entry) {
if (class->usage_mask == 0)
@@ -241,13 +243,13 @@ static int lockdep_stats_show(struct seq_file *m, void *v)
if (class->usage_mask & LOCKF_ENABLED_HARDIRQ_READ)
nr_hardirq_read_unsafe++;
-#ifdef CONFIG_PROVE_LOCKING
sum_forward_deps += lockdep_count_forward_deps(class);
-#endif
}
#ifdef CONFIG_DEBUG_LOCKDEP
DEBUG_LOCKS_WARN_ON(debug_atomic_read(nr_unused_locks) != nr_unused);
#endif
+
+#endif
seq_printf(m, " lock-classes: %11lu [max: %lu]\n",
nr_lock_classes, MAX_LOCKDEP_KEYS);
seq_printf(m, " direct dependencies: %11lu [max: %lu]\n",
diff --git a/kernel/module.c b/kernel/module.c
index 669d81c..8644c18 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -3399,8 +3399,7 @@ static bool finished_loading(const char *name)
sched_annotate_sleep();
mutex_lock(&module_mutex);
mod = find_module_all(name, strlen(name), true);
- ret = !mod || mod->state == MODULE_STATE_LIVE
- || mod->state == MODULE_STATE_GOING;
+ ret = !mod || mod->state == MODULE_STATE_LIVE;
mutex_unlock(&module_mutex);
return ret;
@@ -3570,8 +3569,7 @@ static int add_unformed_module(struct module *mod)
mutex_lock(&module_mutex);
old = find_module_all(mod->name, strlen(mod->name), true);
if (old != NULL) {
- if (old->state == MODULE_STATE_COMING
- || old->state == MODULE_STATE_UNFORMED) {
+ if (old->state != MODULE_STATE_LIVE) {
/* Wait in case it fails to load. */
mutex_unlock(&module_mutex);
err = wait_event_interruptible(module_wq,
diff --git a/kernel/padata.c b/kernel/padata.c
index d568cc5..6c06b30 100644
--- a/kernel/padata.c
+++ b/kernel/padata.c
@@ -267,7 +267,12 @@ static void padata_reorder(struct parallel_data *pd)
* The next object that needs serialization might have arrived to
* the reorder queues in the meantime, we will be called again
* from the timer function if no one else cares for it.
+ *
+ * Ensure reorder_objects is read after pd->lock is dropped so we see
+ * an increment from another task in padata_do_serial. Pairs with
+ * smp_mb__after_atomic in padata_do_serial.
*/
+ smp_mb();
if (atomic_read(&pd->reorder_objects)
&& !(pinst->flags & PADATA_RESET))
mod_timer(&pd->timer, jiffies + HZ);
@@ -387,6 +392,13 @@ void padata_do_serial(struct padata_priv *padata)
list_add_tail(&padata->list, &pqueue->reorder.list);
spin_unlock(&pqueue->reorder.lock);
+ /*
+ * Ensure the atomic_inc of reorder_objects above is ordered correctly
+ * with the trylock of pd->lock in padata_reorder. Pairs with smp_mb
+ * in padata_reorder.
+ */
+ smp_mb__after_atomic();
+
put_cpu();
/* If we're running on the wrong CPU, call padata_reorder() via a
diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c
index 2a2ac53..95271f1 100644
--- a/kernel/pid_namespace.c
+++ b/kernel/pid_namespace.c
@@ -325,7 +325,7 @@ int reboot_pid_ns(struct pid_namespace *pid_ns, int cmd)
}
read_lock(&tasklist_lock);
- force_sig(SIGKILL, pid_ns->child_reaper);
+ send_sig(SIGKILL, pid_ns->child_reaper, 1);
read_unlock(&tasklist_lock);
do_exit(0);
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 733674e..5a29adf 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -5399,7 +5399,7 @@ long __sched io_schedule_timeout(long timeout)
}
EXPORT_SYMBOL(io_schedule_timeout);
-void io_schedule(void)
+void __sched io_schedule(void)
{
int token;
@@ -6381,6 +6381,7 @@ int sched_cpu_starting(unsigned int cpu)
{
sched_rq_cpu_starting(cpu);
sched_tick_start(cpu);
+ clear_walt_request(cpu);
return 0;
}
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index fc2fcfa..e682959 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -1113,6 +1113,21 @@ struct numa_group {
unsigned long faults[0];
};
+/*
+ * For functions that can be called in multiple contexts that permit reading
+ * ->numa_group (see struct task_struct for locking rules).
+ */
+static struct numa_group *deref_task_numa_group(struct task_struct *p)
+{
+ return rcu_dereference_check(p->numa_group, p == current ||
+ (lockdep_is_held(&task_rq(p)->lock) && !READ_ONCE(p->on_cpu)));
+}
+
+static struct numa_group *deref_curr_numa_group(struct task_struct *p)
+{
+ return rcu_dereference_protected(p->numa_group, p == current);
+}
+
static inline unsigned long group_faults_priv(struct numa_group *ng);
static inline unsigned long group_faults_shared(struct numa_group *ng);
@@ -1156,10 +1171,12 @@ static unsigned int task_scan_start(struct task_struct *p)
{
unsigned long smin = task_scan_min(p);
unsigned long period = smin;
+ struct numa_group *ng;
/* Scale the maximum scan period with the amount of shared memory. */
- if (p->numa_group) {
- struct numa_group *ng = p->numa_group;
+ rcu_read_lock();
+ ng = rcu_dereference(p->numa_group);
+ if (ng) {
unsigned long shared = group_faults_shared(ng);
unsigned long private = group_faults_priv(ng);
@@ -1167,6 +1184,7 @@ static unsigned int task_scan_start(struct task_struct *p)
period *= shared + 1;
period /= private + shared + 1;
}
+ rcu_read_unlock();
return max(smin, period);
}
@@ -1175,13 +1193,14 @@ static unsigned int task_scan_max(struct task_struct *p)
{
unsigned long smin = task_scan_min(p);
unsigned long smax;
+ struct numa_group *ng;
/* Watch for min being lower than max due to floor calculations */
smax = sysctl_numa_balancing_scan_period_max / task_nr_scan_windows(p);
/* Scale the maximum scan period with the amount of shared memory. */
- if (p->numa_group) {
- struct numa_group *ng = p->numa_group;
+ ng = deref_curr_numa_group(p);
+ if (ng) {
unsigned long shared = group_faults_shared(ng);
unsigned long private = group_faults_priv(ng);
unsigned long period = smax;
@@ -1213,7 +1232,7 @@ void init_numa_balancing(unsigned long clone_flags, struct task_struct *p)
p->numa_scan_period = sysctl_numa_balancing_scan_delay;
p->numa_work.next = &p->numa_work;
p->numa_faults = NULL;
- p->numa_group = NULL;
+ RCU_INIT_POINTER(p->numa_group, NULL);
p->last_task_numa_placement = 0;
p->last_sum_exec_runtime = 0;
@@ -1260,7 +1279,16 @@ static void account_numa_dequeue(struct rq *rq, struct task_struct *p)
pid_t task_numa_group_id(struct task_struct *p)
{
- return p->numa_group ? p->numa_group->gid : 0;
+ struct numa_group *ng;
+ pid_t gid = 0;
+
+ rcu_read_lock();
+ ng = rcu_dereference(p->numa_group);
+ if (ng)
+ gid = ng->gid;
+ rcu_read_unlock();
+
+ return gid;
}
/*
@@ -1285,11 +1313,13 @@ static inline unsigned long task_faults(struct task_struct *p, int nid)
static inline unsigned long group_faults(struct task_struct *p, int nid)
{
- if (!p->numa_group)
+ struct numa_group *ng = deref_task_numa_group(p);
+
+ if (!ng)
return 0;
- return p->numa_group->faults[task_faults_idx(NUMA_MEM, nid, 0)] +
- p->numa_group->faults[task_faults_idx(NUMA_MEM, nid, 1)];
+ return ng->faults[task_faults_idx(NUMA_MEM, nid, 0)] +
+ ng->faults[task_faults_idx(NUMA_MEM, nid, 1)];
}
static inline unsigned long group_faults_cpu(struct numa_group *group, int nid)
@@ -1427,12 +1457,13 @@ static inline unsigned long task_weight(struct task_struct *p, int nid,
static inline unsigned long group_weight(struct task_struct *p, int nid,
int dist)
{
+ struct numa_group *ng = deref_task_numa_group(p);
unsigned long faults, total_faults;
- if (!p->numa_group)
+ if (!ng)
return 0;
- total_faults = p->numa_group->total_faults;
+ total_faults = ng->total_faults;
if (!total_faults)
return 0;
@@ -1446,7 +1477,7 @@ static inline unsigned long group_weight(struct task_struct *p, int nid,
bool should_numa_migrate_memory(struct task_struct *p, struct page * page,
int src_nid, int dst_cpu)
{
- struct numa_group *ng = p->numa_group;
+ struct numa_group *ng = deref_curr_numa_group(p);
int dst_nid = cpu_to_node(dst_cpu);
int last_cpupid, this_cpupid;
@@ -1651,13 +1682,14 @@ static bool load_too_imbalanced(long src_load, long dst_load,
static void task_numa_compare(struct task_numa_env *env,
long taskimp, long groupimp, bool maymove)
{
+ struct numa_group *cur_ng, *p_ng = deref_curr_numa_group(env->p);
struct rq *dst_rq = cpu_rq(env->dst_cpu);
+ long imp = p_ng ? groupimp : taskimp;
struct task_struct *cur;
long src_load, dst_load;
- long load;
- long imp = env->p->numa_group ? groupimp : taskimp;
- long moveimp = imp;
int dist = env->dist;
+ long moveimp = imp;
+ long load;
if (READ_ONCE(dst_rq->numa_migrate_on))
return;
@@ -1696,21 +1728,22 @@ static void task_numa_compare(struct task_numa_env *env,
* If dst and source tasks are in the same NUMA group, or not
* in any group then look only at task weights.
*/
- if (cur->numa_group == env->p->numa_group) {
+ cur_ng = rcu_dereference(cur->numa_group);
+ if (cur_ng == p_ng) {
imp = taskimp + task_weight(cur, env->src_nid, dist) -
task_weight(cur, env->dst_nid, dist);
/*
* Add some hysteresis to prevent swapping the
* tasks within a group over tiny differences.
*/
- if (cur->numa_group)
+ if (cur_ng)
imp -= imp / 16;
} else {
/*
* Compare the group weights. If a task is all by itself
* (not part of a group), use the task weight instead.
*/
- if (cur->numa_group && env->p->numa_group)
+ if (cur_ng && p_ng)
imp += group_weight(cur, env->src_nid, dist) -
group_weight(cur, env->dst_nid, dist);
else
@@ -1808,11 +1841,12 @@ static int task_numa_migrate(struct task_struct *p)
.best_imp = 0,
.best_cpu = -1,
};
- struct sched_domain *sd;
- struct rq *best_rq;
unsigned long taskweight, groupweight;
- int nid, ret, dist;
+ struct sched_domain *sd;
long taskimp, groupimp;
+ struct numa_group *ng;
+ struct rq *best_rq;
+ int nid, ret, dist;
/*
* Pick the lowest SD_NUMA domain, as that would have the smallest
@@ -1858,7 +1892,8 @@ static int task_numa_migrate(struct task_struct *p)
* multiple NUMA nodes; in order to better consolidate the group,
* we need to check other locations.
*/
- if (env.best_cpu == -1 || (p->numa_group && p->numa_group->active_nodes > 1)) {
+ ng = deref_curr_numa_group(p);
+ if (env.best_cpu == -1 || (ng && ng->active_nodes > 1)) {
for_each_online_node(nid) {
if (nid == env.src_nid || nid == p->numa_preferred_nid)
continue;
@@ -1891,7 +1926,7 @@ static int task_numa_migrate(struct task_struct *p)
* A task that migrated to a second choice node will be better off
* trying for a better one later. Do not set the preferred node here.
*/
- if (p->numa_group) {
+ if (ng) {
if (env.best_cpu == -1)
nid = env.src_nid;
else
@@ -2186,6 +2221,7 @@ static void task_numa_placement(struct task_struct *p)
unsigned long total_faults;
u64 runtime, period;
spinlock_t *group_lock = NULL;
+ struct numa_group *ng;
/*
* The p->mm->numa_scan_seq field gets updated without
@@ -2203,8 +2239,9 @@ static void task_numa_placement(struct task_struct *p)
runtime = numa_get_avg_runtime(p, &period);
/* If the task is part of a group prevent parallel updates to group stats */
- if (p->numa_group) {
- group_lock = &p->numa_group->lock;
+ ng = deref_curr_numa_group(p);
+ if (ng) {
+ group_lock = &ng->lock;
spin_lock_irq(group_lock);
}
@@ -2245,7 +2282,7 @@ static void task_numa_placement(struct task_struct *p)
p->numa_faults[cpu_idx] += f_diff;
faults += p->numa_faults[mem_idx];
p->total_numa_faults += diff;
- if (p->numa_group) {
+ if (ng) {
/*
* safe because we can only change our own group
*
@@ -2253,14 +2290,14 @@ static void task_numa_placement(struct task_struct *p)
* nid and priv in a specific region because it
* is at the beginning of the numa_faults array.
*/
- p->numa_group->faults[mem_idx] += diff;
- p->numa_group->faults_cpu[mem_idx] += f_diff;
- p->numa_group->total_faults += diff;
- group_faults += p->numa_group->faults[mem_idx];
+ ng->faults[mem_idx] += diff;
+ ng->faults_cpu[mem_idx] += f_diff;
+ ng->total_faults += diff;
+ group_faults += ng->faults[mem_idx];
}
}
- if (!p->numa_group) {
+ if (!ng) {
if (faults > max_faults) {
max_faults = faults;
max_nid = nid;
@@ -2271,8 +2308,8 @@ static void task_numa_placement(struct task_struct *p)
}
}
- if (p->numa_group) {
- numa_group_count_active_nodes(p->numa_group);
+ if (ng) {
+ numa_group_count_active_nodes(ng);
spin_unlock_irq(group_lock);
max_nid = preferred_group_nid(p, max_nid);
}
@@ -2306,7 +2343,7 @@ static void task_numa_group(struct task_struct *p, int cpupid, int flags,
int cpu = cpupid_to_cpu(cpupid);
int i;
- if (unlikely(!p->numa_group)) {
+ if (unlikely(!deref_curr_numa_group(p))) {
unsigned int size = sizeof(struct numa_group) +
4*nr_node_ids*sizeof(unsigned long);
@@ -2342,7 +2379,7 @@ static void task_numa_group(struct task_struct *p, int cpupid, int flags,
if (!grp)
goto no_join;
- my_grp = p->numa_group;
+ my_grp = deref_curr_numa_group(p);
if (grp == my_grp)
goto no_join;
@@ -2404,13 +2441,24 @@ static void task_numa_group(struct task_struct *p, int cpupid, int flags,
return;
}
-void task_numa_free(struct task_struct *p)
+/*
+ * Get rid of NUMA staticstics associated with a task (either current or dead).
+ * If @final is set, the task is dead and has reached refcount zero, so we can
+ * safely free all relevant data structures. Otherwise, there might be
+ * concurrent reads from places like load balancing and procfs, and we should
+ * reset the data back to default state without freeing ->numa_faults.
+ */
+void task_numa_free(struct task_struct *p, bool final)
{
- struct numa_group *grp = p->numa_group;
- void *numa_faults = p->numa_faults;
+ /* safe: p either is current or is being freed by current */
+ struct numa_group *grp = rcu_dereference_raw(p->numa_group);
+ unsigned long *numa_faults = p->numa_faults;
unsigned long flags;
int i;
+ if (!numa_faults)
+ return;
+
if (grp) {
spin_lock_irqsave(&grp->lock, flags);
for (i = 0; i < NR_NUMA_HINT_FAULT_STATS * nr_node_ids; i++)
@@ -2423,8 +2471,14 @@ void task_numa_free(struct task_struct *p)
put_numa_group(grp);
}
- p->numa_faults = NULL;
- kfree(numa_faults);
+ if (final) {
+ p->numa_faults = NULL;
+ kfree(numa_faults);
+ } else {
+ p->total_numa_faults = 0;
+ for (i = 0; i < NR_NUMA_HINT_FAULT_STATS * nr_node_ids; i++)
+ numa_faults[i] = 0;
+ }
}
/*
@@ -2477,7 +2531,7 @@ void task_numa_fault(int last_cpupid, int mem_node, int pages, int flags)
* actively using should be counted as local. This allows the
* scan rate to slow down when a workload has settled down.
*/
- ng = p->numa_group;
+ ng = deref_curr_numa_group(p);
if (!priv && !local && ng && ng->active_nodes > 1 &&
numa_is_active_node(cpu_node, ng) &&
numa_is_active_node(mem_node, ng))
@@ -3883,6 +3937,7 @@ struct find_best_target_env {
bool is_rtg;
int placement_boost;
bool need_idle;
+ bool boosted;
int fastpath;
int start_cpu;
};
@@ -6764,6 +6819,7 @@ static int get_start_cpu(struct task_struct *p)
{
struct root_domain *rd = cpu_rq(smp_processor_id())->rd;
int start_cpu = rd->min_cap_orig_cpu;
+ int task_boost = per_task_boost(p);
bool boosted = schedtune_task_boost(p) > 0 ||
task_boost_policy(p) == SCHED_BOOST_ON_BIG;
bool task_skip_min = task_skip_min_cpu(p);
@@ -6773,10 +6829,16 @@ static int get_start_cpu(struct task_struct *p)
* or just mid will be -1, there never be any other combinations of -1s
* beyond these
*/
- if (task_skip_min || boosted) {
+ if (task_skip_min || boosted || task_boost == 1) {
start_cpu = rd->mid_cap_orig_cpu == -1 ?
rd->max_cap_orig_cpu : rd->mid_cap_orig_cpu;
}
+
+ if (task_boost == 2) {
+ start_cpu = rd->max_cap_orig_cpu;
+ return start_cpu;
+ }
+
if (start_cpu == -1 || start_cpu == rd->max_cap_orig_cpu)
return start_cpu;
@@ -6811,7 +6873,7 @@ static void find_best_target(struct sched_domain *sd, cpumask_t *cpus,
unsigned long best_active_cuml_util = ULONG_MAX;
unsigned long best_idle_cuml_util = ULONG_MAX;
bool prefer_idle = schedtune_prefer_idle(p);
- bool boosted = schedtune_task_boost(p) > 0 || per_task_boost(p) > 0;
+ bool boosted = fbt_env->boosted;
/* Initialise with deepest possible cstate (INT_MAX) */
int shallowest_idle_cstate = INT_MAX;
struct sched_domain *start_sd;
@@ -6851,9 +6913,7 @@ static void find_best_target(struct sched_domain *sd, cpumask_t *cpus,
!cpu_isolated(prev_cpu) && cpu_online(prev_cpu) &&
idle_cpu(prev_cpu)) {
- if (idle_get_state_idx(cpu_rq(prev_cpu)) <=
- (is_min_capacity_cpu(prev_cpu) ? 1 : 0)) {
-
+ if (idle_get_state_idx(cpu_rq(prev_cpu)) <= 1) {
target_cpu = prev_cpu;
fbt_env->fastpath = PREV_CPU_FASTPATH;
@@ -7539,7 +7599,8 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu, int sy
int placement_boost = task_boost_policy(p);
u64 start_t = 0;
int delta = 0;
- int boosted = (schedtune_task_boost(p) > 0);
+ int boosted = (schedtune_task_boost(p) > 0) ||
+ (per_task_boost(p) > 0);
int start_cpu = get_start_cpu(p);
if (start_cpu < 0)
@@ -7590,6 +7651,7 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu, int sy
fbt_env.placement_boost = placement_boost;
fbt_env.need_idle = need_idle;
fbt_env.start_cpu = start_cpu;
+ fbt_env.boosted = boosted;
find_best_target(NULL, candidates, p, &fbt_env);
} else {
@@ -12170,18 +12232,22 @@ void show_numa_stats(struct task_struct *p, struct seq_file *m)
{
int node;
unsigned long tsf = 0, tpf = 0, gsf = 0, gpf = 0;
+ struct numa_group *ng;
+ rcu_read_lock();
+ ng = rcu_dereference(p->numa_group);
for_each_online_node(node) {
if (p->numa_faults) {
tsf = p->numa_faults[task_faults_idx(NUMA_MEM, node, 0)];
tpf = p->numa_faults[task_faults_idx(NUMA_MEM, node, 1)];
}
- if (p->numa_group) {
- gsf = p->numa_group->faults[task_faults_idx(NUMA_MEM, node, 0)],
- gpf = p->numa_group->faults[task_faults_idx(NUMA_MEM, node, 1)];
+ if (ng) {
+ gsf = ng->faults[task_faults_idx(NUMA_MEM, node, 0)],
+ gpf = ng->faults[task_faults_idx(NUMA_MEM, node, 1)];
}
print_numa_stats(m, node, tsf, tpf, gsf, gpf);
}
+ rcu_read_unlock();
}
#endif /* CONFIG_NUMA_BALANCING */
#endif /* CONFIG_SCHED_DEBUG */
@@ -12523,6 +12589,7 @@ void check_for_migration(struct rq *rq, struct task_struct *p)
int active_balance;
int new_cpu = -1;
int prev_cpu = task_cpu(p);
+ int ret;
if (rq->misfit_task_load) {
if (rq->curr->state != TASK_RUNNING ||
@@ -12542,9 +12609,13 @@ void check_for_migration(struct rq *rq, struct task_struct *p)
if (active_balance) {
mark_reserved(new_cpu);
raw_spin_unlock(&migration_lock);
- stop_one_cpu_nowait(prev_cpu,
+ ret = stop_one_cpu_nowait(prev_cpu,
active_load_balance_cpu_stop, rq,
&rq->active_balance_work);
+ if (!ret)
+ clear_reserved(new_cpu);
+ else
+ wake_up_if_idle(new_cpu);
return;
}
} else {
diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c
index 2c8719f..c349976 100644
--- a/kernel/sched/idle.c
+++ b/kernel/sched/idle.c
@@ -60,7 +60,8 @@ static noinline int __cpuidle cpu_idle_poll(void)
stop_critical_timings();
while (!tif_need_resched() &&
- (cpu_idle_force_poll || tick_check_broadcast_expired()))
+ (cpu_idle_force_poll || tick_check_broadcast_expired() ||
+ is_reserved(smp_processor_id())))
cpu_relax();
start_critical_timings();
trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
@@ -256,7 +257,8 @@ static void do_idle(void)
* broadcast device expired for us, we don't want to go deep
* idle as we know that the IPI is going to arrive right away.
*/
- if (cpu_idle_force_poll || tick_check_broadcast_expired()) {
+ if (cpu_idle_force_poll || tick_check_broadcast_expired() ||
+ is_reserved(smp_processor_id())) {
tick_nohz_idle_restart_tick();
cpu_idle_poll();
} else {
diff --git a/kernel/sched/sched-pelt.h b/kernel/sched/sched-pelt.h
index a2647367..c529706 100644
--- a/kernel/sched/sched-pelt.h
+++ b/kernel/sched/sched-pelt.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Generated by Documentation/scheduler/sched-pelt; do not modify. */
-static const u32 runnable_avg_yN_inv[] = {
+static const u32 runnable_avg_yN_inv[] __maybe_unused = {
0xffffffff, 0xfa83b2da, 0xf5257d14, 0xefe4b99a, 0xeac0c6e6, 0xe5b906e6,
0xe0ccdeeb, 0xdbfbb796, 0xd744fcc9, 0xd2a81d91, 0xce248c14, 0xc9b9bd85,
0xc5672a10, 0xc12c4cc9, 0xbd08a39e, 0xb8fbaf46, 0xb504f333, 0xb123f581,
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 8497914..85847b6 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -426,7 +426,7 @@ static struct ctl_table kern_table[] = {
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
- .extra1 = &zero,
+ .extra1 = &one,
.extra2 = &two_hundred_fifty_five,
},
#endif
diff --git a/kernel/taskstats.c b/kernel/taskstats.c
index a578d8f51..2dac07a 100644
--- a/kernel/taskstats.c
+++ b/kernel/taskstats.c
@@ -798,6 +798,10 @@ static int taskstats2_foreach(struct sk_buff *skb, struct netlink_callback *cb)
nla = nla_find(nlmsg_attrdata(cb->nlh, GENL_HDRLEN),
nlmsg_attrlen(cb->nlh, GENL_HDRLEN),
TASKSTATS_TYPE_FOREACH);
+
+ if (!nla)
+ goto out;
+
buf = nla_get_u32(nla);
oom_score_min = (short) (buf & 0xFFFF);
oom_score_max = (short) ((buf >> 16) & 0xFFFF);
@@ -854,6 +858,7 @@ static int taskstats2_foreach(struct sk_buff *skb, struct netlink_callback *cb)
}
cb->args[0] = iter.tgid;
+out:
return skb->len;
}
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index 6b23cd5..e1110a7 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -43,6 +43,7 @@ static u64 tick_length_base;
#define MAX_TICKADJ 500LL /* usecs */
#define MAX_TICKADJ_SCALED \
(((MAX_TICKADJ * NSEC_PER_USEC) << NTP_SCALE_SHIFT) / NTP_INTERVAL_FREQ)
+#define MAX_TAI_OFFSET 100000
/*
* phase-lock loop variables
@@ -698,7 +699,8 @@ static inline void process_adjtimex_modes(const struct timex *txc, s32 *time_tai
time_constant = max(time_constant, 0l);
}
- if (txc->modes & ADJ_TAI && txc->constant >= 0)
+ if (txc->modes & ADJ_TAI &&
+ txc->constant >= 0 && txc->constant <= MAX_TAI_OFFSET)
*time_tai = txc->constant;
if (txc->modes & ADJ_OFFSET)
diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c
index d647dab..07afcfe 100644
--- a/kernel/time/timer_list.c
+++ b/kernel/time/timer_list.c
@@ -287,23 +287,6 @@ static inline void timer_list_header(struct seq_file *m, u64 now)
SEQ_printf(m, "\n");
}
-static int timer_list_show(struct seq_file *m, void *v)
-{
- struct timer_list_iter *iter = v;
-
- if (iter->cpu == -1 && !iter->second_pass)
- timer_list_header(m, iter->now);
- else if (!iter->second_pass)
- print_cpu(m, iter->cpu, iter->now);
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
- else if (iter->cpu == -1 && iter->second_pass)
- timer_list_show_tickdevices_header(m);
- else
- print_tickdevice(m, tick_get_device(iter->cpu), iter->cpu);
-#endif
- return 0;
-}
-
void sysrq_timer_list_show(void)
{
u64 now = ktime_to_ns(ktime_get());
@@ -322,6 +305,24 @@ void sysrq_timer_list_show(void)
return;
}
+#ifdef CONFIG_PROC_FS
+static int timer_list_show(struct seq_file *m, void *v)
+{
+ struct timer_list_iter *iter = v;
+
+ if (iter->cpu == -1 && !iter->second_pass)
+ timer_list_header(m, iter->now);
+ else if (!iter->second_pass)
+ print_cpu(m, iter->cpu, iter->now);
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+ else if (iter->cpu == -1 && iter->second_pass)
+ timer_list_show_tickdevices_header(m);
+ else
+ print_tickdevice(m, tick_get_device(iter->cpu), iter->cpu);
+#endif
+ return 0;
+}
+
static void *move_iter(struct timer_list_iter *iter, loff_t offset)
{
for (; offset; offset--) {
@@ -381,3 +382,4 @@ static int __init init_timer_list_procfs(void)
return 0;
}
__initcall(init_timer_list_procfs);
+#endif
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index ec149b7..f322cbf 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1648,6 +1648,11 @@ static bool test_rec_ops_needs_regs(struct dyn_ftrace *rec)
return keep_regs;
}
+static struct ftrace_ops *
+ftrace_find_tramp_ops_any(struct dyn_ftrace *rec);
+static struct ftrace_ops *
+ftrace_find_tramp_ops_next(struct dyn_ftrace *rec, struct ftrace_ops *ops);
+
static bool __ftrace_hash_rec_update(struct ftrace_ops *ops,
int filter_hash,
bool inc)
@@ -1776,15 +1781,17 @@ static bool __ftrace_hash_rec_update(struct ftrace_ops *ops,
}
/*
- * If the rec had TRAMP enabled, then it needs to
- * be cleared. As TRAMP can only be enabled iff
- * there is only a single ops attached to it.
- * In otherwords, always disable it on decrementing.
- * In the future, we may set it if rec count is
- * decremented to one, and the ops that is left
- * has a trampoline.
+ * The TRAMP needs to be set only if rec count
+ * is decremented to one, and the ops that is
+ * left has a trampoline. As TRAMP can only be
+ * enabled if there is only a single ops attached
+ * to it.
*/
- rec->flags &= ~FTRACE_FL_TRAMP;
+ if (ftrace_rec_count(rec) == 1 &&
+ ftrace_find_tramp_ops_any(rec))
+ rec->flags |= FTRACE_FL_TRAMP;
+ else
+ rec->flags &= ~FTRACE_FL_TRAMP;
/*
* flags will be cleared in ftrace_check_record()
@@ -1977,11 +1984,6 @@ static void print_ip_ins(const char *fmt, const unsigned char *p)
printk(KERN_CONT "%s%02x", i ? ":" : "", p[i]);
}
-static struct ftrace_ops *
-ftrace_find_tramp_ops_any(struct dyn_ftrace *rec);
-static struct ftrace_ops *
-ftrace_find_tramp_ops_next(struct dyn_ftrace *rec, struct ftrace_ops *ops);
-
enum ftrace_bug_type ftrace_bug_type;
const void *ftrace_expected;
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 33cbc18..56d2963 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -6089,6 +6089,7 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
struct trace_array *tr = filp->private_data;
struct ring_buffer_event *event;
enum event_trigger_type tt = ETT_NONE;
+ struct trace_entry *trace_entry;
struct ring_buffer *buffer;
struct print_entry *entry;
unsigned long irq_flags;
@@ -6126,7 +6127,8 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
return -EBADF;
entry = ring_buffer_event_data(event);
- entry->ip = _THIS_IP_;
+ trace_entry = (struct trace_entry *)entry;
+ entry->ip = trace_entry->pid;
len = __copy_from_user_inatomic(&entry->buf, ubuf, cnt);
if (len) {
@@ -6146,12 +6148,12 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
if (entry->buf[cnt - 1] != '\n') {
entry->buf[cnt] = '\n';
entry->buf[cnt + 1] = '\0';
- stm_log(OST_ENTITY_TRACE_MARKER, entry->buf, cnt + 2);
+ stm_log(OST_ENTITY_TRACE_MARKER, entry, sizeof(*entry)+cnt + 2);
} else {
entry->buf[cnt] = '\0';
- stm_log(OST_ENTITY_TRACE_MARKER, entry->buf, cnt + 1);
+ stm_log(OST_ENTITY_TRACE_MARKER, entry, sizeof(*entry)+cnt + 1);
}
-
+ entry->ip = _THIS_IP_;
__buffer_unlock_commit(buffer, event);
if (tt)
diff --git a/lib/reed_solomon/decode_rs.c b/lib/reed_solomon/decode_rs.c
index 1db74eb..121beb2 100644
--- a/lib/reed_solomon/decode_rs.c
+++ b/lib/reed_solomon/decode_rs.c
@@ -42,8 +42,18 @@
BUG_ON(pad < 0 || pad >= nn);
/* Does the caller provide the syndrome ? */
- if (s != NULL)
- goto decode;
+ if (s != NULL) {
+ for (i = 0; i < nroots; i++) {
+ /* The syndrome is in index form,
+ * so nn represents zero
+ */
+ if (s[i] != nn)
+ goto decode;
+ }
+
+ /* syndrome is zero, no errors to correct */
+ return 0;
+ }
/* form the syndromes; i.e., evaluate data(x) at roots of
* g(x) */
@@ -99,9 +109,9 @@
if (no_eras > 0) {
/* Init lambda to be the erasure locator polynomial */
lambda[1] = alpha_to[rs_modnn(rs,
- prim * (nn - 1 - eras_pos[0]))];
+ prim * (nn - 1 - (eras_pos[0] + pad)))];
for (i = 1; i < no_eras; i++) {
- u = rs_modnn(rs, prim * (nn - 1 - eras_pos[i]));
+ u = rs_modnn(rs, prim * (nn - 1 - (eras_pos[i] + pad)));
for (j = i + 1; j > 0; j--) {
tmp = index_of[lambda[j - 1]];
if (tmp != nn) {
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index 7c6096a..8c3036c 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -652,17 +652,18 @@ static bool sg_miter_get_next_page(struct sg_mapping_iter *miter)
{
if (!miter->__remaining) {
struct scatterlist *sg;
- unsigned long pgoffset;
if (!__sg_page_iter_next(&miter->piter))
return false;
sg = miter->piter.sg;
- pgoffset = miter->piter.sg_pgoffset;
- miter->__offset = pgoffset ? 0 : sg->offset;
+ miter->__offset = miter->piter.sg_pgoffset ? 0 : sg->offset;
+ miter->piter.sg_pgoffset += miter->__offset >> PAGE_SHIFT;
+ miter->__offset &= PAGE_SIZE - 1;
miter->__remaining = sg->offset + sg->length -
- (pgoffset << PAGE_SHIFT) - miter->__offset;
+ (miter->piter.sg_pgoffset << PAGE_SHIFT) -
+ miter->__offset;
miter->__remaining = min_t(unsigned long, miter->__remaining,
PAGE_SIZE - miter->__offset);
}
diff --git a/lib/test_overflow.c b/lib/test_overflow.c
index fc68056..7a4b6f6 100644
--- a/lib/test_overflow.c
+++ b/lib/test_overflow.c
@@ -486,16 +486,17 @@ static int __init test_overflow_shift(void)
* Deal with the various forms of allocator arguments. See comments above
* the DEFINE_TEST_ALLOC() instances for mapping of the "bits".
*/
-#define alloc010(alloc, arg, sz) alloc(sz, GFP_KERNEL)
-#define alloc011(alloc, arg, sz) alloc(sz, GFP_KERNEL, NUMA_NO_NODE)
+#define alloc_GFP (GFP_KERNEL | __GFP_NOWARN)
+#define alloc010(alloc, arg, sz) alloc(sz, alloc_GFP)
+#define alloc011(alloc, arg, sz) alloc(sz, alloc_GFP, NUMA_NO_NODE)
#define alloc000(alloc, arg, sz) alloc(sz)
#define alloc001(alloc, arg, sz) alloc(sz, NUMA_NO_NODE)
-#define alloc110(alloc, arg, sz) alloc(arg, sz, GFP_KERNEL)
+#define alloc110(alloc, arg, sz) alloc(arg, sz, alloc_GFP)
#define free0(free, arg, ptr) free(ptr)
#define free1(free, arg, ptr) free(arg, ptr)
-/* Wrap around to 8K */
-#define TEST_SIZE (9 << PAGE_SHIFT)
+/* Wrap around to 16K */
+#define TEST_SIZE (5 * 4096)
#define DEFINE_TEST_ALLOC(func, free_func, want_arg, want_gfp, want_node)\
static int __init test_ ## func (void *arg) \
diff --git a/lib/test_string.c b/lib/test_string.c
index 0fcdb82d..98a787e 100644
--- a/lib/test_string.c
+++ b/lib/test_string.c
@@ -35,7 +35,7 @@ static __init int memset16_selftest(void)
fail:
kfree(p);
if (i < 256)
- return (i << 24) | (j << 16) | k;
+ return (i << 24) | (j << 16) | k | 0x8000;
return 0;
}
@@ -71,7 +71,7 @@ static __init int memset32_selftest(void)
fail:
kfree(p);
if (i < 256)
- return (i << 24) | (j << 16) | k;
+ return (i << 24) | (j << 16) | k | 0x8000;
return 0;
}
@@ -107,7 +107,7 @@ static __init int memset64_selftest(void)
fail:
kfree(p);
if (i < 256)
- return (i << 24) | (j << 16) | k;
+ return (i << 24) | (j << 16) | k | 0x8000;
return 0;
}
diff --git a/mm/cma.c b/mm/cma.c
index 672ced1..d3973af 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -18,11 +18,6 @@
#define pr_fmt(fmt) "cma: " fmt
-#ifdef CONFIG_CMA_DEBUG
-#ifndef DEBUG
-# define DEBUG
-#endif
-#endif
#define CREATE_TRACE_POINTS
#include <linux/memblock.h>
@@ -313,6 +308,12 @@ int __init cma_declare_contiguous(phys_addr_t base,
*/
alignment = max(alignment, (phys_addr_t)PAGE_SIZE <<
max_t(unsigned long, MAX_ORDER - 1, pageblock_order));
+ if (fixed && base & (alignment - 1)) {
+ ret = -EINVAL;
+ pr_err("Region at %pa must be aligned to %pa bytes\n",
+ &base, &alignment);
+ goto err;
+ }
base = ALIGN(base, alignment);
size = ALIGN(size, alignment);
limit &= ~(alignment - 1);
@@ -343,6 +344,13 @@ int __init cma_declare_contiguous(phys_addr_t base,
if (limit == 0 || limit > memblock_end)
limit = memblock_end;
+ if (base + size > limit) {
+ ret = -EINVAL;
+ pr_err("Size (%pa) of region at %pa exceeds limit (%pa)\n",
+ &size, &base, &limit);
+ goto err;
+ }
+
/* Reserve memory */
if (fixed) {
if (memblock_is_region_reserved(base, size) ||
diff --git a/mm/filemap.c b/mm/filemap.c
index 815fec2..0b794ee 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -568,6 +568,28 @@ int filemap_fdatawait_range(struct address_space *mapping, loff_t start_byte,
EXPORT_SYMBOL(filemap_fdatawait_range);
/**
+ * filemap_fdatawait_range_keep_errors - wait for writeback to complete
+ * @mapping: address space structure to wait for
+ * @start_byte: offset in bytes where the range starts
+ * @end_byte: offset in bytes where the range ends (inclusive)
+ *
+ * Walk the list of under-writeback pages of the given address space in the
+ * given range and wait for all of them. Unlike filemap_fdatawait_range(),
+ * this function does not clear error status of the address space.
+ *
+ * Use this function if callers don't handle errors themselves. Expected
+ * call sites are system-wide / filesystem-wide data flushers: e.g. sync(2),
+ * fsfreeze(8)
+ */
+int filemap_fdatawait_range_keep_errors(struct address_space *mapping,
+ loff_t start_byte, loff_t end_byte)
+{
+ __filemap_fdatawait_range(mapping, start_byte, end_byte);
+ return filemap_check_and_keep_errors(mapping);
+}
+EXPORT_SYMBOL(filemap_fdatawait_range_keep_errors);
+
+/**
* file_fdatawait_range - wait for writeback to complete
* @file: file pointing to address space structure to wait for
* @start_byte: offset in bytes where the range starts
diff --git a/mm/gup.c b/mm/gup.c
index caadd31..f3088d2 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -458,11 +458,14 @@ static int get_gate_page(struct mm_struct *mm, unsigned long address,
pgd = pgd_offset_k(address);
else
pgd = pgd_offset_gate(mm, address);
- BUG_ON(pgd_none(*pgd));
+ if (pgd_none(*pgd))
+ return -EFAULT;
p4d = p4d_offset(pgd, address);
- BUG_ON(p4d_none(*p4d));
+ if (p4d_none(*p4d))
+ return -EFAULT;
pud = pud_offset(p4d, address);
- BUG_ON(pud_none(*pud));
+ if (pud_none(*pud))
+ return -EFAULT;
pmd = pmd_offset(pud, address);
if (!pmd_present(*pmd))
return -EFAULT;
@@ -1367,7 +1370,8 @@ static inline pte_t gup_get_pte(pte_t *ptep)
}
#endif
-static void undo_dev_pagemap(int *nr, int nr_start, struct page **pages)
+static void __maybe_unused undo_dev_pagemap(int *nr, int nr_start,
+ struct page **pages)
{
while ((*nr) - nr_start) {
struct page *page = pages[--(*nr)];
diff --git a/mm/kmemleak.c b/mm/kmemleak.c
index a606745..aa0338c 100644
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -588,7 +588,7 @@ static struct kmemleak_object *create_object(unsigned long ptr, size_t size,
if (in_irq()) {
object->pid = 0;
strncpy(object->comm, "hardirq", sizeof(object->comm));
- } else if (in_softirq()) {
+ } else if (in_serving_softirq()) {
object->pid = 0;
strncpy(object->comm, "softirq", sizeof(object->comm));
} else {
diff --git a/mm/memory.c b/mm/memory.c
index b009e8c..fc9c36b 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -4982,7 +4982,9 @@ int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
void *old_buf = buf;
int write = gup_flags & FOLL_WRITE;
- down_read(&mm->mmap_sem);
+ if (down_read_killable(&mm->mmap_sem))
+ return 0;
+
/* ignore errors, just check how much was successfully transferred */
while (len) {
int bytes, ret, offset;
diff --git a/mm/mmu_notifier.c b/mm/mmu_notifier.c
index 82bb1a9..06dedb1 100644
--- a/mm/mmu_notifier.c
+++ b/mm/mmu_notifier.c
@@ -316,7 +316,7 @@ static int do_mmu_notifier_register(struct mmu_notifier *mn,
* thanks to mm_take_all_locks().
*/
spin_lock(&mm->mmu_notifier_mm->lock);
- hlist_add_head(&mn->hlist, &mm->mmu_notifier_mm->list);
+ hlist_add_head_rcu(&mn->hlist, &mm->mmu_notifier_mm->list);
spin_unlock(&mm->mmu_notifier_mm->lock);
mm_drop_all_locks(mm);
diff --git a/mm/nommu.c b/mm/nommu.c
index e4aac33..1d63ecf 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -1779,7 +1779,8 @@ int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
struct vm_area_struct *vma;
int write = gup_flags & FOLL_WRITE;
- down_read(&mm->mmap_sem);
+ if (down_read_killable(&mm->mmap_sem))
+ return 0;
/* the access must start within one of the target process's mappings */
vma = find_vma(mm, addr);
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 0af8992..e75789d 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -52,11 +52,13 @@
#define CREATE_TRACE_POINTS
#include <trace/events/oom.h>
+#define ULMK_MAGIC "lmkd"
+
int sysctl_panic_on_oom =
IS_ENABLED(CONFIG_DEBUG_PANIC_ON_OOM) ? 2 : 0;
int sysctl_oom_kill_allocating_task;
int sysctl_oom_dump_tasks = 1;
-int sysctl_reap_mem_on_sigkill;
+int sysctl_reap_mem_on_sigkill = 1;
/*
* Serializes oom killer invocations (out_of_memory()) from all contexts to
@@ -1230,30 +1232,6 @@ void pagefault_out_of_memory(void)
mutex_unlock(&oom_lock);
}
-/* Call this function with task_lock being held as we're accessing ->mm */
-void dump_killed_info(struct task_struct *selected)
-{
- int selected_tasksize = get_mm_rss(selected->mm);
-
- pr_info_ratelimited("Killing '%s' (%d), adj %hd,\n"
- " to free %ldkB on behalf of '%s' (%d)\n"
- " Free CMA is %ldkB\n"
- " Total reserve is %ldkB\n"
- " Total free pages is %ldkB\n"
- " Total file cache is %ldkB\n",
- selected->comm, selected->pid,
- selected->signal->oom_score_adj,
- selected_tasksize * (long)(PAGE_SIZE / 1024),
- current->comm, current->pid,
- global_zone_page_state(NR_FREE_CMA_PAGES) *
- (long)(PAGE_SIZE / 1024),
- totalreserve_pages * (long)(PAGE_SIZE / 1024),
- global_zone_page_state(NR_FREE_PAGES) *
- (long)(PAGE_SIZE / 1024),
- global_node_page_state(NR_FILE_PAGES) *
- (long)(PAGE_SIZE / 1024));
-}
-
void add_to_oom_reaper(struct task_struct *p)
{
static DEFINE_RATELIMIT_STATE(reaper_rs, DEFAULT_RATELIMIT_INTERVAL,
@@ -1272,10 +1250,10 @@ void add_to_oom_reaper(struct task_struct *p)
wake_oom_reaper(p);
}
- dump_killed_info(p);
task_unlock(p);
- if (__ratelimit(&reaper_rs) && p->signal->oom_score_adj == 0) {
+ if (strcmp(current->comm, ULMK_MAGIC) && __ratelimit(&reaper_rs)
+ && p->signal->oom_score_adj == 0) {
show_mem(SHOW_MEM_FILTER_NODES, NULL);
show_mem_call_notifiers();
if (sysctl_oom_dump_tasks)
diff --git a/mm/swap.c b/mm/swap.c
index 55b88f1..c481066 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -740,15 +740,20 @@ void release_pages(struct page **pages, int nr)
if (is_huge_zero_page(page))
continue;
- /* Device public page can not be huge page */
- if (is_device_public_page(page)) {
+ if (is_zone_device_page(page)) {
if (locked_pgdat) {
spin_unlock_irqrestore(&locked_pgdat->lru_lock,
flags);
locked_pgdat = NULL;
}
- put_devmap_managed_page(page);
- continue;
+ /*
+ * ZONE_DEVICE pages that return 'false' from
+ * put_devmap_managed_page() do not require special
+ * processing, and instead, expect a call to
+ * put_page_testzero().
+ */
+ if (put_devmap_managed_page(page))
+ continue;
}
page = compound_head(page);
diff --git a/mm/vmscan.c b/mm/vmscan.c
index e1aed44..3d12b19 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -694,7 +694,14 @@ static unsigned long shrink_slab(gfp_t gfp_mask, int nid,
unsigned long ret, freed = 0;
struct shrinker *shrinker;
- if (!mem_cgroup_is_root(memcg))
+ /*
+ * The root memcg might be allocated even though memcg is disabled
+ * via "cgroup_disable=memory" boot parameter. This could make
+ * mem_cgroup_is_root() return false, then just run memcg slab
+ * shrink, but skip global shrink. This may result in premature
+ * oom.
+ */
+ if (!mem_cgroup_disabled() && !mem_cgroup_is_root(memcg))
return shrink_slab_memcg(gfp_mask, nid, memcg, priority);
if (!down_read_trylock(&shrinker_rwsem))
@@ -2262,7 +2269,7 @@ static void shrink_active_list(unsigned long nr_to_scan,
* 10TB 320 32GB
*/
static bool inactive_list_is_low(struct lruvec *lruvec, bool file,
- struct scan_control *sc, bool actual_reclaim)
+ struct scan_control *sc, bool trace)
{
enum lru_list active_lru = file * LRU_FILE + LRU_ACTIVE;
struct pglist_data *pgdat = lruvec_pgdat(lruvec);
@@ -2288,7 +2295,7 @@ static bool inactive_list_is_low(struct lruvec *lruvec, bool file,
* rid of the stale workingset quickly.
*/
refaults = lruvec_page_state(lruvec, WORKINGSET_ACTIVATE);
- if (file && actual_reclaim && lruvec->refaults != refaults) {
+ if (file && lruvec->refaults != refaults) {
inactive_ratio = 0;
} else {
gb = (inactive + active) >> (30 - PAGE_SHIFT);
@@ -2298,7 +2305,7 @@ static bool inactive_list_is_low(struct lruvec *lruvec, bool file,
inactive_ratio = 1;
}
- if (actual_reclaim)
+ if (trace)
trace_mm_vmscan_inactive_list_is_low(pgdat->node_id, sc->reclaim_idx,
lruvec_lru_size(lruvec, inactive_lru, MAX_NR_ZONES), inactive,
lruvec_lru_size(lruvec, active_lru, MAX_NR_ZONES), active,
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
index eb596c2..8493362 100644
--- a/net/9p/trans_virtio.c
+++ b/net/9p/trans_virtio.c
@@ -782,10 +782,16 @@ static struct p9_trans_module p9_virtio_trans = {
/* The standard init function */
static int __init p9_virtio_init(void)
{
+ int rc;
+
INIT_LIST_HEAD(&virtio_chan_list);
v9fs_register_trans(&p9_virtio_trans);
- return register_virtio_driver(&p9_virtio_drv);
+ rc = register_virtio_driver(&p9_virtio_drv);
+ if (rc)
+ v9fs_unregister_trans(&p9_virtio_trans);
+
+ return rc;
}
static void __exit p9_virtio_cleanup(void)
diff --git a/net/9p/trans_xen.c b/net/9p/trans_xen.c
index e2fbf36..9daab0d 100644
--- a/net/9p/trans_xen.c
+++ b/net/9p/trans_xen.c
@@ -530,13 +530,19 @@ static struct xenbus_driver xen_9pfs_front_driver = {
static int p9_trans_xen_init(void)
{
+ int rc;
+
if (!xen_domain())
return -ENODEV;
pr_info("Initialising Xen transport for 9pfs\n");
v9fs_register_trans(&p9_xen_trans);
- return xenbus_register_frontend(&xen_9pfs_front_driver);
+ rc = xenbus_register_frontend(&xen_9pfs_front_driver);
+ if (rc)
+ v9fs_unregister_trans(&p9_xen_trans);
+
+ return rc;
}
module_init(p9_trans_xen_init);
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
index 73bf6a9..0b7b36f 100644
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -2485,7 +2485,7 @@ batadv_iv_ogm_neigh_is_sob(struct batadv_neigh_node *neigh1,
return ret;
}
-static void batadv_iv_iface_activate(struct batadv_hard_iface *hard_iface)
+static void batadv_iv_iface_enabled(struct batadv_hard_iface *hard_iface)
{
/* begin scheduling originator messages on that interface */
batadv_iv_ogm_schedule(hard_iface);
@@ -2825,8 +2825,8 @@ static void batadv_iv_gw_dump(struct sk_buff *msg, struct netlink_callback *cb,
static struct batadv_algo_ops batadv_batman_iv __read_mostly = {
.name = "BATMAN_IV",
.iface = {
- .activate = batadv_iv_iface_activate,
.enable = batadv_iv_ogm_iface_enable,
+ .enabled = batadv_iv_iface_enabled,
.disable = batadv_iv_ogm_iface_disable,
.update_mac = batadv_iv_ogm_iface_update_mac,
.primary_set = batadv_iv_ogm_primary_iface_set,
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index 08690d0..36f0962 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -821,6 +821,9 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
batadv_hardif_recalc_extra_skbroom(soft_iface);
+ if (bat_priv->algo_ops->iface.enabled)
+ bat_priv->algo_ops->iface.enabled(hard_iface);
+
out:
return 0;
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 359ec1a..9fa5389 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -3821,6 +3821,8 @@ static void batadv_tt_purge(struct work_struct *work)
*/
void batadv_tt_free(struct batadv_priv *bat_priv)
{
+ batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_ROAM, 1);
+
batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_TT, 1);
batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_TT, 1);
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index eeee3e6..fdba8a1 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -2130,6 +2130,9 @@ struct batadv_algo_iface_ops {
/** @enable: init routing info when hard-interface is enabled */
int (*enable)(struct batadv_hard_iface *hard_iface);
+ /** @enabled: notification when hard-interface was enabled (optional) */
+ void (*enabled)(struct batadv_hard_iface *hard_iface);
+
/** @disable: de-init routing info when hard-interface is disabled */
void (*disable)(struct batadv_hard_iface *hard_iface);
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index 4e2576f..357475c 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -187,10 +187,16 @@ static inline struct lowpan_peer *peer_lookup_dst(struct lowpan_btle_dev *dev,
}
if (!rt) {
- nexthop = &lowpan_cb(skb)->gw;
-
- if (ipv6_addr_any(nexthop))
- return NULL;
+ if (ipv6_addr_any(&lowpan_cb(skb)->gw)) {
+ /* There is neither route nor gateway,
+ * probably the destination is a direct peer.
+ */
+ nexthop = daddr;
+ } else {
+ /* There is a known gateway
+ */
+ nexthop = &lowpan_cb(skb)->gw;
+ }
} else {
nexthop = rt6_nexthop(rt, daddr);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 3e7badb..0adcddb 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -5545,6 +5545,11 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev,
return send_conn_param_neg_reply(hdev, handle,
HCI_ERROR_UNKNOWN_CONN_ID);
+ if (min < hcon->le_conn_min_interval ||
+ max > hcon->le_conn_max_interval)
+ return send_conn_param_neg_reply(hdev, handle,
+ HCI_ERROR_INVALID_LL_PARAMS);
+
if (hci_check_conn_params(min, max, latency, timeout))
return send_conn_param_neg_reply(hdev, handle,
HCI_ERROR_INVALID_LL_PARAMS);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 879d543..a54dadf 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -4384,6 +4384,12 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn,
l2cap_chan_lock(chan);
+ if (chan->state != BT_DISCONN) {
+ l2cap_chan_unlock(chan);
+ mutex_unlock(&conn->chan_lock);
+ return 0;
+ }
+
l2cap_chan_hold(chan);
l2cap_chan_del(chan, 0);
@@ -5281,7 +5287,14 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
memset(&rsp, 0, sizeof(rsp));
- err = hci_check_conn_params(min, max, latency, to_multiplier);
+ if (min < hcon->le_conn_min_interval ||
+ max > hcon->le_conn_max_interval) {
+ BT_DBG("requested connection interval exceeds current bounds.");
+ err = -EINVAL;
+ } else {
+ err = hci_check_conn_params(min, max, latency, to_multiplier);
+ }
+
if (err)
rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
else
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index a1c1b7e..cc2f7ca 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -2580,6 +2580,19 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,
goto distribute;
}
+ /* Drop IRK if peer is using identity address during pairing but is
+ * providing different address as identity information.
+ *
+ * Microsoft Surface Precision Mouse is known to have this bug.
+ */
+ if (hci_is_identity_address(&hcon->dst, hcon->dst_type) &&
+ (bacmp(&info->bdaddr, &hcon->dst) ||
+ info->addr_type != hcon->dst_type)) {
+ bt_dev_err(hcon->hdev,
+ "ignoring IRK with invalid identity address");
+ goto distribute;
+ }
+
bacpy(&smp->id_addr, &info->bdaddr);
smp->id_addr_type = info->addr_type;
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index fed0ff4..2532c1a 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -79,7 +79,6 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
struct net_bridge_fdb_entry *dst = NULL;
struct net_bridge_mdb_entry *mdst;
bool local_rcv, mcast_hit = false;
- const unsigned char *dest;
struct net_bridge *br;
u16 vid = 0;
@@ -97,10 +96,9 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
br_fdb_update(br, p, eth_hdr(skb)->h_source, vid, false);
local_rcv = !!(br->dev->flags & IFF_PROMISC);
- dest = eth_hdr(skb)->h_dest;
- if (is_multicast_ether_addr(dest)) {
+ if (is_multicast_ether_addr(eth_hdr(skb)->h_dest)) {
/* by definition the broadcast is also a multicast address */
- if (is_broadcast_ether_addr(dest)) {
+ if (is_broadcast_ether_addr(eth_hdr(skb)->h_dest)) {
pkt_type = BR_PKT_BROADCAST;
local_rcv = true;
} else {
@@ -150,7 +148,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
}
break;
case BR_PKT_UNICAST:
- dst = br_fdb_find_rcu(br, dest, vid);
+ dst = br_fdb_find_rcu(br, eth_hdr(skb)->h_dest, vid);
default:
break;
}
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 75901c4..6a362da 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1147,6 +1147,7 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
int type;
int err = 0;
__be32 group;
+ u16 nsrcs;
ih = igmpv3_report_hdr(skb);
num = ntohs(ih->ngrec);
@@ -1160,8 +1161,9 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
grec = (void *)(skb->data + len - sizeof(*grec));
group = grec->grec_mca;
type = grec->grec_type;
+ nsrcs = ntohs(grec->grec_nsrcs);
- len += ntohs(grec->grec_nsrcs) * 4;
+ len += nsrcs * 4;
if (!pskb_may_pull(skb, len))
return -EINVAL;
@@ -1182,7 +1184,7 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
src = eth_hdr(skb)->h_source;
if ((type == IGMPV3_CHANGE_TO_INCLUDE ||
type == IGMPV3_MODE_IS_INCLUDE) &&
- ntohs(grec->grec_nsrcs) == 0) {
+ nsrcs == 0) {
br_ip4_multicast_leave_group(br, port, group, vid, src);
} else {
err = br_ip4_multicast_add_group(br, port, group, vid,
@@ -1217,23 +1219,26 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
len = skb_transport_offset(skb) + sizeof(*icmp6h);
for (i = 0; i < num; i++) {
- __be16 *nsrcs, _nsrcs;
+ __be16 *_nsrcs, __nsrcs;
+ u16 nsrcs;
- nsrcs = skb_header_pointer(skb,
- len + offsetof(struct mld2_grec,
- grec_nsrcs),
- sizeof(_nsrcs), &_nsrcs);
- if (!nsrcs)
+ _nsrcs = skb_header_pointer(skb,
+ len + offsetof(struct mld2_grec,
+ grec_nsrcs),
+ sizeof(__nsrcs), &__nsrcs);
+ if (!_nsrcs)
return -EINVAL;
+ nsrcs = ntohs(*_nsrcs);
+
if (!pskb_may_pull(skb,
len + sizeof(*grec) +
- sizeof(struct in6_addr) * ntohs(*nsrcs)))
+ sizeof(struct in6_addr) * nsrcs))
return -EINVAL;
grec = (struct mld2_grec *)(skb->data + len);
len += sizeof(*grec) +
- sizeof(struct in6_addr) * ntohs(*nsrcs);
+ sizeof(struct in6_addr) * nsrcs;
/* We treat these as MLDv1 reports for now. */
switch (grec->grec_type) {
@@ -1252,7 +1257,7 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
src = eth_hdr(skb)->h_source;
if ((grec->grec_type == MLD2_CHANGE_TO_INCLUDE ||
grec->grec_type == MLD2_MODE_IS_INCLUDE) &&
- ntohs(*nsrcs) == 0) {
+ nsrcs == 0) {
br_ip6_multicast_leave_group(br, port, &grec->grec_mca,
vid, src);
} else {
@@ -1505,7 +1510,6 @@ static int br_ip6_multicast_query(struct net_bridge *br,
struct sk_buff *skb,
u16 vid)
{
- const struct ipv6hdr *ip6h = ipv6_hdr(skb);
struct mld_msg *mld;
struct net_bridge_mdb_entry *mp;
struct mld2_query *mld2q;
@@ -1549,7 +1553,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
if (is_general_query) {
saddr.proto = htons(ETH_P_IPV6);
- saddr.u.ip6 = ip6h->saddr;
+ saddr.u.ip6 = ipv6_hdr(skb)->saddr;
br_multicast_query_received(br, port, &br->ip6_other_query,
&saddr, max_delay);
@@ -1617,6 +1621,9 @@ br_multicast_leave_group(struct net_bridge *br,
if (!br_port_group_equal(p, port, src))
continue;
+ if (p->flags & MDB_PG_FLAGS_PERMANENT)
+ break;
+
rcu_assign_pointer(*pp, p->next);
hlist_del_init(&p->mglist);
del_timer(&p->timer);
diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c
index 1b75d6b..37ddcea 100644
--- a/net/bridge/br_stp_bpdu.c
+++ b/net/bridge/br_stp_bpdu.c
@@ -147,7 +147,6 @@ void br_send_tcn_bpdu(struct net_bridge_port *p)
void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb,
struct net_device *dev)
{
- const unsigned char *dest = eth_hdr(skb)->h_dest;
struct net_bridge_port *p;
struct net_bridge *br;
const unsigned char *buf;
@@ -176,7 +175,7 @@ void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb,
if (p->state == BR_STATE_DISABLED)
goto out;
- if (!ether_addr_equal(dest, br->group_addr))
+ if (!ether_addr_equal(eth_hdr(skb)->h_dest, br->group_addr))
goto out;
if (p->flags & BR_BPDU_GUARD) {
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
index 7df2690..5f3950f 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -677,6 +677,11 @@ void br_vlan_flush(struct net_bridge *br)
ASSERT_RTNL();
+ /* delete auto-added default pvid local fdb before flushing vlans
+ * otherwise it will be leaked on bridge device init failure
+ */
+ br_fdb_delete_by_port(br, NULL, 0, 1);
+
vg = br_vlan_group(br);
__vlan_flush(vg);
RCU_INIT_POINTER(br->vlgrp, NULL);
diff --git a/net/can/af_can.c b/net/can/af_can.c
index e386d65..04132b0 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -959,6 +959,8 @@ static struct pernet_operations can_pernet_ops __read_mostly = {
static __init int can_init(void)
{
+ int err;
+
/* check for correct padding to be able to use the structs similarly */
BUILD_BUG_ON(offsetof(struct can_frame, can_dlc) !=
offsetof(struct canfd_frame, len) ||
@@ -972,15 +974,31 @@ static __init int can_init(void)
if (!rcv_cache)
return -ENOMEM;
- register_pernet_subsys(&can_pernet_ops);
+ err = register_pernet_subsys(&can_pernet_ops);
+ if (err)
+ goto out_pernet;
/* protocol register */
- sock_register(&can_family_ops);
- register_netdevice_notifier(&can_netdev_notifier);
+ err = sock_register(&can_family_ops);
+ if (err)
+ goto out_sock;
+ err = register_netdevice_notifier(&can_netdev_notifier);
+ if (err)
+ goto out_notifier;
+
dev_add_pack(&can_packet);
dev_add_pack(&canfd_packet);
return 0;
+
+out_notifier:
+ sock_unregister(PF_CAN);
+out_sock:
+ unregister_pernet_subsys(&can_pernet_ops);
+out_pernet:
+ kmem_cache_destroy(rcv_cache);
+
+ return err;
}
static __exit void can_exit(void)
diff --git a/net/core/dev.c b/net/core/dev.c
index c5887ed..e369e1b 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -9540,6 +9540,8 @@ static void __net_exit default_device_exit(struct net *net)
/* Push remaining network devices to init_net */
snprintf(fb_name, IFNAMSIZ, "dev%d", dev->ifindex);
+ if (__dev_get_by_name(&init_net, fb_name))
+ snprintf(fb_name, IFNAMSIZ, "dev%%d");
err = dev_change_net_namespace(dev, &init_net, fb_name);
if (err) {
pr_emerg("%s: failed to move %s to init_net: %d\n",
diff --git a/net/core/filter.c b/net/core/filter.c
index 34ec932..c996380 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -3991,7 +3991,7 @@ BPF_CALL_5(bpf_setsockopt, struct bpf_sock_ops_kern *, bpf_sock,
TCP_CA_NAME_MAX-1));
name[TCP_CA_NAME_MAX-1] = 0;
ret = tcp_set_congestion_control(sk, name, false,
- reinit);
+ reinit, true);
} else {
struct tcp_sock *tp = tcp_sk(sk);
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 74b77bc..ff55da2 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1021,6 +1021,7 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
atomic_set(&neigh->probes,
NEIGH_VAR(neigh->parms, UCAST_PROBES));
+ neigh_del_timer(neigh);
neigh->nud_state = NUD_INCOMPLETE;
neigh->updated = now;
next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
@@ -1037,6 +1038,7 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
}
} else if (neigh->nud_state & NUD_STALE) {
neigh_dbg(2, "neigh %p is delayed\n", neigh);
+ neigh_del_timer(neigh);
neigh->nud_state = NUD_DELAY;
neigh->updated = jiffies;
neigh_add_timer(neigh, jiffies +
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 8b57681..9b9f696 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2302,6 +2302,7 @@ int skb_send_sock_locked(struct sock *sk, struct sk_buff *skb, int offset,
kv.iov_base = skb->data + offset;
kv.iov_len = slen;
memset(&msg, 0, sizeof(msg));
+ msg.msg_flags = MSG_DONTWAIT;
ret = kernel_sendmsg_locked(sk, &msg, &kv, 1, slen);
if (ret <= 0)
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 87045be..41412ed 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -66,6 +66,11 @@
#include <net/net_namespace.h>
#include <net/addrconf.h>
+#define IPV6ONLY_FLAGS \
+ (IFA_F_NODAD | IFA_F_OPTIMISTIC | IFA_F_DADFAILED | \
+ IFA_F_HOMEADDRESS | IFA_F_TENTATIVE | \
+ IFA_F_MANAGETEMPADDR | IFA_F_STABLE_PRIVACY)
+
static struct ipv4_devconf ipv4_devconf = {
.data = {
[IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
@@ -462,6 +467,9 @@ static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
ifa->ifa_flags &= ~IFA_F_SECONDARY;
last_primary = &in_dev->ifa_list;
+ /* Don't set IPv6 only flags to IPv4 addresses */
+ ifa->ifa_flags &= ~IPV6ONLY_FLAGS;
+
for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
ifap = &ifa1->ifa_next) {
if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index d187ee8..b2240b7 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -1218,12 +1218,8 @@ static void igmpv3_del_delrec(struct in_device *in_dev, struct ip_mc_list *im)
if (pmc) {
im->interface = pmc->interface;
if (im->sfmode == MCAST_INCLUDE) {
- im->tomb = pmc->tomb;
- pmc->tomb = NULL;
-
- im->sources = pmc->sources;
- pmc->sources = NULL;
-
+ swap(im->tomb, pmc->tomb);
+ swap(im->sources, pmc->sources);
for (psf = im->sources; psf; psf = psf->sf_next)
psf->sf_crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
} else {
diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c
index c248e0d..67ef9d8 100644
--- a/net/ipv4/ip_tunnel_core.c
+++ b/net/ipv4/ip_tunnel_core.c
@@ -89,9 +89,12 @@ void iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb,
__ip_select_ident(net, iph, skb_shinfo(skb)->gso_segs ?: 1);
err = ip_local_out(net, sk, skb);
- if (unlikely(net_xmit_eval(err)))
- pkt_len = 0;
- iptunnel_xmit_stats(dev, pkt_len);
+
+ if (dev) {
+ if (unlikely(net_xmit_eval(err)))
+ pkt_len = 0;
+ iptunnel_xmit_stats(dev, pkt_len);
+ }
}
EXPORT_SYMBOL_GPL(iptunnel_xmit);
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index c891235..4368282 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -281,6 +281,9 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb,
const struct iphdr *tiph = &tunnel->parms.iph;
u8 ipproto;
+ if (!pskb_inet_may_pull(skb))
+ goto tx_error;
+
switch (skb->protocol) {
case htons(ETH_P_IP):
ipproto = IPPROTO_IPIP;
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 0370ec4..3ed0789 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2594,6 +2594,8 @@ int tcp_disconnect(struct sock *sk, int flags)
tcp_saved_syn_free(tp);
tp->compressed_ack = 0;
tp->bytes_sent = 0;
+ tp->bytes_acked = 0;
+ tp->bytes_received = 0;
tp->bytes_retrans = 0;
tp->dsack_dups = 0;
tp->reord_seen = 0;
@@ -2729,7 +2731,9 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
name[val] = 0;
lock_sock(sk);
- err = tcp_set_congestion_control(sk, name, true, true);
+ err = tcp_set_congestion_control(sk, name, true, true,
+ ns_capable(sock_net(sk)->user_ns,
+ CAP_NET_ADMIN));
release_sock(sk);
return err;
}
diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c
index bc6c02f..48f79db 100644
--- a/net/ipv4/tcp_cong.c
+++ b/net/ipv4/tcp_cong.c
@@ -332,7 +332,8 @@ int tcp_set_allowed_congestion_control(char *val)
* tcp_reinit_congestion_control (if the current congestion control was
* already initialized.
*/
-int tcp_set_congestion_control(struct sock *sk, const char *name, bool load, bool reinit)
+int tcp_set_congestion_control(struct sock *sk, const char *name, bool load,
+ bool reinit, bool cap_net_admin)
{
struct inet_connection_sock *icsk = inet_csk(sk);
const struct tcp_congestion_ops *ca;
@@ -368,8 +369,7 @@ int tcp_set_congestion_control(struct sock *sk, const char *name, bool load, boo
} else {
err = -EBUSY;
}
- } else if (!((ca->flags & TCP_CONG_NON_RESTRICTED) ||
- ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))) {
+ } else if (!((ca->flags & TCP_CONG_NON_RESTRICTED) || cap_net_admin)) {
err = -EPERM;
} else if (!try_module_get(ca->owner)) {
err = -EBUSY;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 9bdbfb3..8454512 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -1272,6 +1272,7 @@ int tcp_fragment(struct sock *sk, enum tcp_queue tcp_queue,
struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *buff;
int nsize, old_factor;
+ long limit;
int nlen;
u8 flags;
@@ -1282,8 +1283,16 @@ int tcp_fragment(struct sock *sk, enum tcp_queue tcp_queue,
if (nsize < 0)
nsize = 0;
- if (unlikely((sk->sk_wmem_queued >> 1) > sk->sk_sndbuf &&
- tcp_queue != TCP_FRAG_IN_WRITE_QUEUE)) {
+ /* tcp_sendmsg() can overshoot sk_wmem_queued by one full size skb.
+ * We need some allowance to not penalize applications setting small
+ * SO_SNDBUF values.
+ * Also allow first and last skb in retransmit queue to be split.
+ */
+ limit = sk->sk_sndbuf + 2 * SKB_TRUESIZE(GSO_MAX_SIZE);
+ if (unlikely((sk->sk_wmem_queued >> 1) > limit &&
+ tcp_queue != TCP_FRAG_IN_WRITE_QUEUE &&
+ skb != tcp_rtx_queue_head(sk) &&
+ skb != tcp_rtx_queue_tail(sk))) {
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPWQUEUETOOBIG);
return -ENOMEM;
}
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index a6c0479..bbb5ffb 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -1081,8 +1081,24 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
err = call_fib6_entry_notifiers(info->nl_net,
FIB_EVENT_ENTRY_ADD,
rt, extack);
- if (err)
+ if (err) {
+ struct fib6_info *sibling, *next_sibling;
+
+ /* If the route has siblings, then it first
+ * needs to be unlinked from them.
+ */
+ if (!rt->fib6_nsiblings)
+ return err;
+
+ list_for_each_entry_safe(sibling, next_sibling,
+ &rt->fib6_siblings,
+ fib6_siblings)
+ sibling->fib6_nsiblings--;
+ rt->fib6_nsiblings = 0;
+ list_del_init(&rt->fib6_siblings);
+ rt6_multipath_rebalance(next_sibling);
return err;
+ }
rcu_assign_pointer(rt->fib6_next, iter);
atomic_inc(&rt->fib6_ref);
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index 01ecd51..a53ef07 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -680,12 +680,13 @@ static int prepare_ip6gre_xmit_ipv6(struct sk_buff *skb,
struct flowi6 *fl6, __u8 *dsfield,
int *encap_limit)
{
- struct ipv6hdr *ipv6h = ipv6_hdr(skb);
+ struct ipv6hdr *ipv6h;
struct ip6_tnl *t = netdev_priv(dev);
__u16 offset;
offset = ip6_tnl_parse_tlv_enc_lim(skb, skb_network_header(skb));
/* ip6_tnl_parse_tlv_enc_lim() might have reallocated skb->head */
+ ipv6h = ipv6_hdr(skb);
if (offset > 0) {
struct ipv6_tlv_tnl_enc_lim *tel;
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index ade1390..d0ad85b 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -1283,12 +1283,11 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
}
fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
+ dsfield = INET_ECN_encapsulate(dsfield, ipv4_get_dsfield(iph));
if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6))
return -1;
- dsfield = INET_ECN_encapsulate(dsfield, ipv4_get_dsfield(iph));
-
skb_set_inner_ipproto(skb, IPPROTO_IPIP);
err = ip6_tnl_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu,
@@ -1372,12 +1371,11 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
}
fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
+ dsfield = INET_ECN_encapsulate(dsfield, ipv6_get_dsfield(ipv6h));
if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6))
return -1;
- dsfield = INET_ECN_encapsulate(dsfield, ipv6_get_dsfield(ipv6h));
-
skb_set_inner_ipproto(skb, IPPROTO_IPV6);
err = ip6_tnl_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu,
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 673a4a9..45d8d08 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -197,6 +197,7 @@ static inline int ndisc_is_useropt(const struct net_device *dev,
{
return opt->nd_opt_type == ND_OPT_RDNSS ||
opt->nd_opt_type == ND_OPT_DNSSL ||
+ opt->nd_opt_type == ND_OPT_CAPTIVE_PORTAL ||
ndisc_ops_is_useropt(dev, opt->nd_opt_type);
}
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 271a5c6..a792a80 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -2214,7 +2214,7 @@ static struct dst_entry *rt6_check(struct rt6_info *rt,
{
u32 rt_cookie = 0;
- if ((from && !fib6_get_cookie_safe(from, &rt_cookie)) ||
+ if (!from || !fib6_get_cookie_safe(from, &rt_cookie) ||
rt_cookie != cookie)
return NULL;
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 0b79c9a..1982f9f 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -2442,8 +2442,10 @@ static int key_pol_get_resp(struct sock *sk, struct xfrm_policy *xp, const struc
goto out;
}
err = pfkey_xfrm_policy2msg(out_skb, xp, dir);
- if (err < 0)
+ if (err < 0) {
+ kfree_skb(out_skb);
goto out;
+ }
out_hdr = (struct sadb_msg *) out_skb->data;
out_hdr->sadb_msg_version = hdr->sadb_msg_version;
@@ -2694,8 +2696,10 @@ static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr)
return PTR_ERR(out_skb);
err = pfkey_xfrm_policy2msg(out_skb, xp, dir);
- if (err < 0)
+ if (err < 0) {
+ kfree_skb(out_skb);
return err;
+ }
out_hdr = (struct sadb_msg *) out_skb->data;
out_hdr->sadb_msg_version = pfk->dump.msg_version;
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index 04d9946..c095678 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -1686,6 +1686,9 @@ static const struct proto_ops pppol2tp_ops = {
.recvmsg = pppol2tp_recvmsg,
.mmap = sock_no_mmap,
.ioctl = pppox_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = pppox_compat_ioctl,
+#endif
};
static const struct pppox_proto pppol2tp_proto = {
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 35c6dfa..cfd3067 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1410,7 +1410,7 @@ ieee80211_get_sband(struct ieee80211_sub_if_data *sdata)
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
- if (WARN_ON(!chanctx_conf)) {
+ if (WARN_ON_ONCE(!chanctx_conf)) {
rcu_read_unlock();
return NULL;
}
@@ -1999,6 +1999,13 @@ void __ieee80211_flush_queues(struct ieee80211_local *local,
static inline bool ieee80211_can_run_worker(struct ieee80211_local *local)
{
/*
+ * It's unsafe to try to do any work during reconfigure flow.
+ * When the flow ends the work will be requeued.
+ */
+ if (local->in_reconfig)
+ return false;
+
+ /*
* If quiescing is set, we are racing with __ieee80211_suspend.
* __ieee80211_suspend flushes the workers after setting quiescing,
* and we check quiescing / suspended before enqueing new workers.
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index d51da26..3162f95 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -923,6 +923,7 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
/* flush STAs and mpaths on this iface */
sta_info_flush(sdata);
+ ieee80211_free_keys(sdata, true);
mesh_path_flush_by_iface(sdata);
/* stop the beacon */
@@ -1212,7 +1213,8 @@ int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata)
ifmsh->chsw_ttl = 0;
/* Remove the CSA and MCSP elements from the beacon */
- tmp_csa_settings = rcu_dereference(ifmsh->csa);
+ tmp_csa_settings = rcu_dereference_protected(ifmsh->csa,
+ lockdep_is_held(&sdata->wdev.mtx));
RCU_INIT_POINTER(ifmsh->csa, NULL);
if (tmp_csa_settings)
kfree_rcu(tmp_csa_settings, rcu_head);
@@ -1234,6 +1236,8 @@ int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata,
struct mesh_csa_settings *tmp_csa_settings;
int ret = 0;
+ lockdep_assert_held(&sdata->wdev.mtx);
+
tmp_csa_settings = kmalloc(sizeof(*tmp_csa_settings),
GFP_ATOMIC);
if (!tmp_csa_settings)
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 2558a34..c596385 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2224,6 +2224,10 @@ int ieee80211_reconfig(struct ieee80211_local *local)
mutex_lock(&local->mtx);
ieee80211_start_next_roc(local);
mutex_unlock(&local->mtx);
+
+ /* Requeue all works */
+ list_for_each_entry(sdata, &local->interfaces, list)
+ ieee80211_queue_work(&local->hw, &sdata->work);
}
ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP,
diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h
index 8a33dac..ddfe06d 100644
--- a/net/netfilter/ipset/ip_set_hash_gen.h
+++ b/net/netfilter/ipset/ip_set_hash_gen.h
@@ -625,7 +625,7 @@ mtype_resize(struct ip_set *set, bool retried)
goto cleanup;
}
m->size = AHASH_INIT_SIZE;
- extsize = ext_size(AHASH_INIT_SIZE, dsize);
+ extsize += ext_size(AHASH_INIT_SIZE, dsize);
RCU_INIT_POINTER(hbucket(t, key), m);
} else if (m->pos >= m->size) {
struct hbucket *ht;
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 62c0e80..a71f777 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -2218,7 +2218,6 @@ static const struct nf_hook_ops ip_vs_ops[] = {
static int __net_init __ip_vs_init(struct net *net)
{
struct netns_ipvs *ipvs;
- int ret;
ipvs = net_generic(net, ip_vs_net_id);
if (ipvs == NULL)
@@ -2250,17 +2249,11 @@ static int __net_init __ip_vs_init(struct net *net)
if (ip_vs_sync_net_init(ipvs) < 0)
goto sync_fail;
- ret = nf_register_net_hooks(net, ip_vs_ops, ARRAY_SIZE(ip_vs_ops));
- if (ret < 0)
- goto hook_fail;
-
return 0;
/*
* Error handling
*/
-hook_fail:
- ip_vs_sync_net_cleanup(ipvs);
sync_fail:
ip_vs_conn_net_cleanup(ipvs);
conn_fail:
@@ -2290,6 +2283,19 @@ static void __net_exit __ip_vs_cleanup(struct net *net)
net->ipvs = NULL;
}
+static int __net_init __ip_vs_dev_init(struct net *net)
+{
+ int ret;
+
+ ret = nf_register_net_hooks(net, ip_vs_ops, ARRAY_SIZE(ip_vs_ops));
+ if (ret < 0)
+ goto hook_fail;
+ return 0;
+
+hook_fail:
+ return ret;
+}
+
static void __net_exit __ip_vs_dev_cleanup(struct net *net)
{
struct netns_ipvs *ipvs = net_ipvs(net);
@@ -2309,6 +2315,7 @@ static struct pernet_operations ipvs_core_ops = {
};
static struct pernet_operations ipvs_core_dev_ops = {
+ .init = __ip_vs_dev_init,
.exit = __ip_vs_dev_cleanup,
};
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index 2d4e048..3df94a4 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -2382,9 +2382,7 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
cfg.syncid = dm->syncid;
ret = start_sync_thread(ipvs, &cfg, dm->state);
} else {
- mutex_lock(&ipvs->sync_mutex);
ret = stop_sync_thread(ipvs, dm->state);
- mutex_unlock(&ipvs->sync_mutex);
}
goto out_dec;
}
@@ -3492,10 +3490,8 @@ static int ip_vs_genl_del_daemon(struct netns_ipvs *ipvs, struct nlattr **attrs)
if (!attrs[IPVS_DAEMON_ATTR_STATE])
return -EINVAL;
- mutex_lock(&ipvs->sync_mutex);
ret = stop_sync_thread(ipvs,
nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE]));
- mutex_unlock(&ipvs->sync_mutex);
return ret;
}
diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c
index d4020c5..ecb7106 100644
--- a/net/netfilter/ipvs/ip_vs_sync.c
+++ b/net/netfilter/ipvs/ip_vs_sync.c
@@ -195,6 +195,7 @@ union ip_vs_sync_conn {
#define IPVS_OPT_F_PARAM (1 << (IPVS_OPT_PARAM-1))
struct ip_vs_sync_thread_data {
+ struct task_struct *task;
struct netns_ipvs *ipvs;
struct socket *sock;
char *buf;
@@ -374,8 +375,11 @@ static inline void sb_queue_tail(struct netns_ipvs *ipvs,
max(IPVS_SYNC_SEND_DELAY, 1));
ms->sync_queue_len++;
list_add_tail(&sb->list, &ms->sync_queue);
- if ((++ms->sync_queue_delay) == IPVS_SYNC_WAKEUP_RATE)
- wake_up_process(ms->master_thread);
+ if ((++ms->sync_queue_delay) == IPVS_SYNC_WAKEUP_RATE) {
+ int id = (int)(ms - ipvs->ms);
+
+ wake_up_process(ipvs->master_tinfo[id].task);
+ }
} else
ip_vs_sync_buff_release(sb);
spin_unlock(&ipvs->sync_lock);
@@ -1636,8 +1640,10 @@ static void master_wakeup_work_handler(struct work_struct *work)
spin_lock_bh(&ipvs->sync_lock);
if (ms->sync_queue_len &&
ms->sync_queue_delay < IPVS_SYNC_WAKEUP_RATE) {
+ int id = (int)(ms - ipvs->ms);
+
ms->sync_queue_delay = IPVS_SYNC_WAKEUP_RATE;
- wake_up_process(ms->master_thread);
+ wake_up_process(ipvs->master_tinfo[id].task);
}
spin_unlock_bh(&ipvs->sync_lock);
}
@@ -1703,10 +1709,6 @@ static int sync_thread_master(void *data)
if (sb)
ip_vs_sync_buff_release(sb);
- /* release the sending multicast socket */
- sock_release(tinfo->sock);
- kfree(tinfo);
-
return 0;
}
@@ -1740,11 +1742,6 @@ static int sync_thread_backup(void *data)
}
}
- /* release the sending multicast socket */
- sock_release(tinfo->sock);
- kfree(tinfo->buf);
- kfree(tinfo);
-
return 0;
}
@@ -1752,8 +1749,8 @@ static int sync_thread_backup(void *data)
int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c,
int state)
{
- struct ip_vs_sync_thread_data *tinfo = NULL;
- struct task_struct **array = NULL, *task;
+ struct ip_vs_sync_thread_data *ti = NULL, *tinfo;
+ struct task_struct *task;
struct net_device *dev;
char *name;
int (*threadfn)(void *data);
@@ -1822,7 +1819,7 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c,
threadfn = sync_thread_master;
} else if (state == IP_VS_STATE_BACKUP) {
result = -EEXIST;
- if (ipvs->backup_threads)
+ if (ipvs->backup_tinfo)
goto out_early;
ipvs->bcfg = *c;
@@ -1849,28 +1846,22 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c,
master_wakeup_work_handler);
ms->ipvs = ipvs;
}
- } else {
- array = kcalloc(count, sizeof(struct task_struct *),
- GFP_KERNEL);
- result = -ENOMEM;
- if (!array)
- goto out;
}
+ result = -ENOMEM;
+ ti = kcalloc(count, sizeof(struct ip_vs_sync_thread_data),
+ GFP_KERNEL);
+ if (!ti)
+ goto out;
for (id = 0; id < count; id++) {
- result = -ENOMEM;
- tinfo = kmalloc(sizeof(*tinfo), GFP_KERNEL);
- if (!tinfo)
- goto out;
+ tinfo = &ti[id];
tinfo->ipvs = ipvs;
- tinfo->sock = NULL;
if (state == IP_VS_STATE_BACKUP) {
+ result = -ENOMEM;
tinfo->buf = kmalloc(ipvs->bcfg.sync_maxlen,
GFP_KERNEL);
if (!tinfo->buf)
goto out;
- } else {
- tinfo->buf = NULL;
}
tinfo->id = id;
if (state == IP_VS_STATE_MASTER)
@@ -1885,17 +1876,15 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c,
result = PTR_ERR(task);
goto out;
}
- tinfo = NULL;
- if (state == IP_VS_STATE_MASTER)
- ipvs->ms[id].master_thread = task;
- else
- array[id] = task;
+ tinfo->task = task;
}
/* mark as active */
- if (state == IP_VS_STATE_BACKUP)
- ipvs->backup_threads = array;
+ if (state == IP_VS_STATE_MASTER)
+ ipvs->master_tinfo = ti;
+ else
+ ipvs->backup_tinfo = ti;
spin_lock_bh(&ipvs->sync_buff_lock);
ipvs->sync_state |= state;
spin_unlock_bh(&ipvs->sync_buff_lock);
@@ -1910,29 +1899,31 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c,
out:
/* We do not need RTNL lock anymore, release it here so that
- * sock_release below and in the kthreads can use rtnl_lock
- * to leave the mcast group.
+ * sock_release below can use rtnl_lock to leave the mcast group.
*/
rtnl_unlock();
- count = id;
- while (count-- > 0) {
- if (state == IP_VS_STATE_MASTER)
- kthread_stop(ipvs->ms[count].master_thread);
- else
- kthread_stop(array[count]);
+ id = min(id, count - 1);
+ if (ti) {
+ for (tinfo = ti + id; tinfo >= ti; tinfo--) {
+ if (tinfo->task)
+ kthread_stop(tinfo->task);
+ }
}
if (!(ipvs->sync_state & IP_VS_STATE_MASTER)) {
kfree(ipvs->ms);
ipvs->ms = NULL;
}
mutex_unlock(&ipvs->sync_mutex);
- if (tinfo) {
- if (tinfo->sock)
- sock_release(tinfo->sock);
- kfree(tinfo->buf);
- kfree(tinfo);
+
+ /* No more mutexes, release socks */
+ if (ti) {
+ for (tinfo = ti + id; tinfo >= ti; tinfo--) {
+ if (tinfo->sock)
+ sock_release(tinfo->sock);
+ kfree(tinfo->buf);
+ }
+ kfree(ti);
}
- kfree(array);
return result;
out_early:
@@ -1944,15 +1935,18 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c,
int stop_sync_thread(struct netns_ipvs *ipvs, int state)
{
- struct task_struct **array;
+ struct ip_vs_sync_thread_data *ti, *tinfo;
int id;
int retc = -EINVAL;
IP_VS_DBG(7, "%s(): pid %d\n", __func__, task_pid_nr(current));
+ mutex_lock(&ipvs->sync_mutex);
if (state == IP_VS_STATE_MASTER) {
+ retc = -ESRCH;
if (!ipvs->ms)
- return -ESRCH;
+ goto err;
+ ti = ipvs->master_tinfo;
/*
* The lock synchronizes with sb_queue_tail(), so that we don't
@@ -1971,38 +1965,56 @@ int stop_sync_thread(struct netns_ipvs *ipvs, int state)
struct ipvs_master_sync_state *ms = &ipvs->ms[id];
int ret;
+ tinfo = &ti[id];
pr_info("stopping master sync thread %d ...\n",
- task_pid_nr(ms->master_thread));
+ task_pid_nr(tinfo->task));
cancel_delayed_work_sync(&ms->master_wakeup_work);
- ret = kthread_stop(ms->master_thread);
+ ret = kthread_stop(tinfo->task);
if (retc >= 0)
retc = ret;
}
kfree(ipvs->ms);
ipvs->ms = NULL;
+ ipvs->master_tinfo = NULL;
} else if (state == IP_VS_STATE_BACKUP) {
- if (!ipvs->backup_threads)
- return -ESRCH;
+ retc = -ESRCH;
+ if (!ipvs->backup_tinfo)
+ goto err;
+ ti = ipvs->backup_tinfo;
ipvs->sync_state &= ~IP_VS_STATE_BACKUP;
- array = ipvs->backup_threads;
retc = 0;
for (id = ipvs->threads_mask; id >= 0; id--) {
int ret;
+ tinfo = &ti[id];
pr_info("stopping backup sync thread %d ...\n",
- task_pid_nr(array[id]));
- ret = kthread_stop(array[id]);
+ task_pid_nr(tinfo->task));
+ ret = kthread_stop(tinfo->task);
if (retc >= 0)
retc = ret;
}
- kfree(array);
- ipvs->backup_threads = NULL;
+ ipvs->backup_tinfo = NULL;
+ } else {
+ goto err;
}
+ id = ipvs->threads_mask;
+ mutex_unlock(&ipvs->sync_mutex);
+
+ /* No more mutexes, release socks */
+ for (tinfo = ti + id; tinfo >= ti; tinfo--) {
+ if (tinfo->sock)
+ sock_release(tinfo->sock);
+ kfree(tinfo->buf);
+ }
+ kfree(ti);
/* decrease the module use count */
ip_vs_use_count_dec();
+ return retc;
+err:
+ mutex_unlock(&ipvs->sync_mutex);
return retc;
}
@@ -2021,7 +2033,6 @@ void ip_vs_sync_net_cleanup(struct netns_ipvs *ipvs)
{
int retc;
- mutex_lock(&ipvs->sync_mutex);
retc = stop_sync_thread(ipvs, IP_VS_STATE_MASTER);
if (retc && retc != -ESRCH)
pr_err("Failed to stop Master Daemon\n");
@@ -2029,5 +2040,4 @@ void ip_vs_sync_net_cleanup(struct netns_ipvs *ipvs)
retc = stop_sync_thread(ipvs, IP_VS_STATE_BACKUP);
if (retc && retc != -ESRCH)
pr_err("Failed to stop Backup Daemon\n");
- mutex_unlock(&ipvs->sync_mutex);
}
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
index 7569ba0..a96a8c1 100644
--- a/net/netfilter/nf_queue.c
+++ b/net/netfilter/nf_queue.c
@@ -174,6 +174,11 @@ static int __nf_queue(struct sk_buff *skb, const struct nf_hook_state *state,
goto err;
}
+ if (!skb_dst_force(skb) && state->hook != NF_INET_PRE_ROUTING) {
+ status = -ENETDOWN;
+ goto err;
+ }
+
*entry = (struct nf_queue_entry) {
.skb = skb,
.state = *state,
@@ -182,7 +187,6 @@ static int __nf_queue(struct sk_buff *skb, const struct nf_hook_state *state,
};
nf_queue_entry_get_refs(entry);
- skb_dst_force(skb);
switch (entry->state.pf) {
case AF_INET:
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index 71ffd1a..43910e5 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -872,7 +872,7 @@ int nr_rx_frame(struct sk_buff *skb, struct net_device *dev)
unsigned short frametype, flags, window, timeout;
int ret;
- skb->sk = NULL; /* Initially we don't know who it's for */
+ skb_orphan(skb);
/*
* skb->data points to the netrom frame start
@@ -970,7 +970,9 @@ int nr_rx_frame(struct sk_buff *skb, struct net_device *dev)
window = skb->data[20];
+ sock_hold(make);
skb->sk = make;
+ skb->destructor = sock_efree;
make->sk_state = TCP_ESTABLISHED;
/* Fill in his circuit details */
diff --git a/net/nfc/nci/data.c b/net/nfc/nci/data.c
index 908f25e..5405d07 100644
--- a/net/nfc/nci/data.c
+++ b/net/nfc/nci/data.c
@@ -119,7 +119,7 @@ static int nci_queue_tx_data_frags(struct nci_dev *ndev,
conn_info = nci_get_conn_info_by_conn_id(ndev, conn_id);
if (!conn_info) {
rc = -EPROTO;
- goto free_exit;
+ goto exit;
}
__skb_queue_head_init(&frags_q);
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
index 85ae53d..8211e8e 100644
--- a/net/openvswitch/actions.c
+++ b/net/openvswitch/actions.c
@@ -175,8 +175,7 @@ static void update_ethertype(struct sk_buff *skb, struct ethhdr *hdr,
if (skb->ip_summed == CHECKSUM_COMPLETE) {
__be16 diff[] = { ~(hdr->h_proto), ethertype };
- skb->csum = ~csum_partial((char *)diff, sizeof(diff),
- ~skb->csum);
+ skb->csum = csum_partial((char *)diff, sizeof(diff), skb->csum);
}
hdr->h_proto = ethertype;
@@ -268,8 +267,7 @@ static int set_mpls(struct sk_buff *skb, struct sw_flow_key *flow_key,
if (skb->ip_summed == CHECKSUM_COMPLETE) {
__be32 diff[] = { ~(stack->label_stack_entry), lse };
- skb->csum = ~csum_partial((char *)diff, sizeof(diff),
- ~skb->csum);
+ skb->csum = csum_partial((char *)diff, sizeof(diff), skb->csum);
}
stack->label_stack_entry = lse;
diff --git a/net/qrtr/fifo.c b/net/qrtr/fifo.c
index 0a494a6..4a1dd07 100644
--- a/net/qrtr/fifo.c
+++ b/net/qrtr/fifo.c
@@ -341,7 +341,7 @@ static int qrtr_fifo_xprt_probe(struct platform_device *pdev)
qrtr_fifo_config_init(xprtp);
xprtp->ep.xmit = xprt_write;
- ret = qrtr_endpoint_register(&xprtp->ep, QRTR_EP_NID_AUTO);
+ ret = qrtr_endpoint_register(&xprtp->ep, QRTR_EP_NID_AUTO, false);
if (ret)
return ret;
diff --git a/net/qrtr/mhi.c b/net/qrtr/mhi.c
index b864b6b..788177e 100644
--- a/net/qrtr/mhi.c
+++ b/net/qrtr/mhi.c
@@ -145,6 +145,7 @@ static int qcom_mhi_qrtr_probe(struct mhi_device *mhi_dev,
{
struct qrtr_mhi_dev *qdev;
u32 net_id;
+ bool rt;
int rc;
qdev = devm_kzalloc(&mhi_dev->dev, sizeof(*qdev), GFP_KERNEL);
@@ -160,10 +161,12 @@ static int qcom_mhi_qrtr_probe(struct mhi_device *mhi_dev,
if (rc < 0)
net_id = QRTR_EP_NET_ID_AUTO;
+ rt = of_property_read_bool(mhi_dev->dev.of_node, "qcom,low-latency");
+
INIT_LIST_HEAD(&qdev->ul_pkts);
spin_lock_init(&qdev->ul_lock);
- rc = qrtr_endpoint_register(&qdev->ep, net_id);
+ rc = qrtr_endpoint_register(&qdev->ep, net_id, rt);
if (rc)
return rc;
diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c
index d994a90..3a3378c 100644
--- a/net/qrtr/qrtr.c
+++ b/net/qrtr/qrtr.c
@@ -22,6 +22,7 @@
#include <linux/uidgid.h>
#include <net/sock.h>
+#include <uapi/linux/sched/types.h>
#include "qrtr.h"
@@ -921,13 +922,16 @@ static void qrtr_node_rx_work(struct kthread_work *work)
* qrtr_endpoint_register() - register a new endpoint
* @ep: endpoint to register
* @nid: desired node id; may be QRTR_EP_NID_AUTO for auto-assignment
+ * @rt: flag to notify real time low latency endpoint
* Return: 0 on success; negative error code on failure
*
* The specified endpoint must have the xmit function pointer set on call.
*/
-int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int net_id)
+int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int net_id,
+ bool rt)
{
struct qrtr_node *node;
+ struct sched_param param = {.sched_priority = 1};
if (!ep || !ep->xmit)
return -EINVAL;
@@ -950,6 +954,8 @@ int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int net_id)
kfree(node);
return -ENOMEM;
}
+ if (rt)
+ sched_setscheduler(node->task, SCHED_FIFO, ¶m);
mutex_init(&node->qrtr_tx_lock);
INIT_RADIX_TREE(&node->qrtr_tx_flow, GFP_KERNEL);
diff --git a/net/qrtr/qrtr.h b/net/qrtr/qrtr.h
index f9aede4..6a2cccb 100644
--- a/net/qrtr/qrtr.h
+++ b/net/qrtr/qrtr.h
@@ -26,7 +26,8 @@ struct qrtr_endpoint {
struct qrtr_node *node;
};
-int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int net_id);
+int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int net_id,
+ bool rt);
void qrtr_endpoint_unregister(struct qrtr_endpoint *ep);
diff --git a/net/qrtr/smd.c b/net/qrtr/smd.c
index 0c78f15..fff9720 100644
--- a/net/qrtr/smd.c
+++ b/net/qrtr/smd.c
@@ -60,6 +60,7 @@ static int qcom_smd_qrtr_probe(struct rpmsg_device *rpdev)
{
struct qrtr_smd_dev *qdev;
u32 net_id;
+ bool rt;
int rc;
qdev = devm_kzalloc(&rpdev->dev, sizeof(*qdev), GFP_KERNEL);
@@ -74,7 +75,9 @@ static int qcom_smd_qrtr_probe(struct rpmsg_device *rpdev)
if (rc < 0)
net_id = QRTR_EP_NET_ID_AUTO;
- rc = qrtr_endpoint_register(&qdev->ep, net_id);
+ rt = of_property_read_bool(rpdev->dev.of_node, "qcom,low-latency");
+
+ rc = qrtr_endpoint_register(&qdev->ep, net_id, rt);
if (rc)
return rc;
diff --git a/net/qrtr/usb.c b/net/qrtr/usb.c
index fd71df9..3daecca 100644
--- a/net/qrtr/usb.c
+++ b/net/qrtr/usb.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/* Copyright (c) 2018, The Linux Foundation. All rights reserved. */
+/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. */
#include <linux/kthread.h>
#include <linux/module.h>
@@ -213,7 +213,7 @@ static int qcom_usb_qrtr_probe(struct usb_interface *interface,
init_usb_anchor(&qdev->submitted);
- rc = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NID_AUTO);
+ rc = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NID_AUTO, false);
if (rc)
return rc;
@@ -263,7 +263,7 @@ static int qcom_usb_qrtr_reset_resume(struct usb_interface *intf)
int rc = 0;
qrtr_endpoint_unregister(&qdev->ep);
- rc = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NID_AUTO);
+ rc = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NID_AUTO, false);
if (rc)
return rc;
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
index 3c39b880..d76e5e5 100644
--- a/net/rxrpc/af_rxrpc.c
+++ b/net/rxrpc/af_rxrpc.c
@@ -552,6 +552,7 @@ static int rxrpc_sendmsg(struct socket *sock, struct msghdr *m, size_t len)
switch (rx->sk.sk_state) {
case RXRPC_UNBOUND:
+ case RXRPC_CLIENT_UNBOUND:
rx->srx.srx_family = AF_RXRPC;
rx->srx.srx_service = 0;
rx->srx.transport_type = SOCK_DGRAM;
@@ -576,10 +577,9 @@ static int rxrpc_sendmsg(struct socket *sock, struct msghdr *m, size_t len)
}
rx->local = local;
- rx->sk.sk_state = RXRPC_CLIENT_UNBOUND;
+ rx->sk.sk_state = RXRPC_CLIENT_BOUND;
/* Fall through */
- case RXRPC_CLIENT_UNBOUND:
case RXRPC_CLIENT_BOUND:
if (!m->msg_name &&
test_bit(RXRPC_SOCK_CONNECTED, &rx->flags)) {
diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c
index 0c68bc9..20fae5c 100644
--- a/net/sched/act_bpf.c
+++ b/net/sched/act_bpf.c
@@ -287,6 +287,7 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
struct tcf_bpf *prog;
bool is_bpf, is_ebpf;
int ret, res = 0;
+ u32 index;
if (!nla)
return -EINVAL;
@@ -299,13 +300,13 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
return -EINVAL;
parm = nla_data(tb[TCA_ACT_BPF_PARMS]);
-
- ret = tcf_idr_check_alloc(tn, &parm->index, act, bind);
+ index = parm->index;
+ ret = tcf_idr_check_alloc(tn, &index, act, bind);
if (!ret) {
- ret = tcf_idr_create(tn, parm->index, est, act,
+ ret = tcf_idr_create(tn, index, est, act,
&act_bpf_ops, bind, true);
if (ret < 0) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return ret;
}
diff --git a/net/sched/act_connmark.c b/net/sched/act_connmark.c
index 6f0f273..6054367 100644
--- a/net/sched/act_connmark.c
+++ b/net/sched/act_connmark.c
@@ -104,6 +104,7 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla,
struct tcf_connmark_info *ci;
struct tc_connmark *parm;
int ret = 0;
+ u32 index;
if (!nla)
return -EINVAL;
@@ -117,13 +118,13 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla,
return -EINVAL;
parm = nla_data(tb[TCA_CONNMARK_PARMS]);
-
- ret = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ index = parm->index;
+ ret = tcf_idr_check_alloc(tn, &index, a, bind);
if (!ret) {
- ret = tcf_idr_create(tn, parm->index, est, a,
+ ret = tcf_idr_create(tn, index, est, a,
&act_connmark_ops, bind, false);
if (ret) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return ret;
}
diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c
index b8a67ae..4043719 100644
--- a/net/sched/act_csum.c
+++ b/net/sched/act_csum.c
@@ -55,6 +55,7 @@ static int tcf_csum_init(struct net *net, struct nlattr *nla,
struct tc_csum *parm;
struct tcf_csum *p;
int ret = 0, err;
+ u32 index;
if (nla == NULL)
return -EINVAL;
@@ -66,13 +67,13 @@ static int tcf_csum_init(struct net *net, struct nlattr *nla,
if (tb[TCA_CSUM_PARMS] == NULL)
return -EINVAL;
parm = nla_data(tb[TCA_CSUM_PARMS]);
-
- err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ index = parm->index;
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
if (!err) {
- ret = tcf_idr_create(tn, parm->index, est, a,
+ ret = tcf_idr_create(tn, index, est, a,
&act_csum_ops, bind, true);
if (ret) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return ret;
}
ret = ACT_P_CREATED;
diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c
index cd1d9bd..72d3347 100644
--- a/net/sched/act_gact.c
+++ b/net/sched/act_gact.c
@@ -64,6 +64,7 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
struct tc_gact *parm;
struct tcf_gact *gact;
int ret = 0;
+ u32 index;
int err;
#ifdef CONFIG_GACT_PROB
struct tc_gact_p *p_parm = NULL;
@@ -79,6 +80,7 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
if (tb[TCA_GACT_PARMS] == NULL)
return -EINVAL;
parm = nla_data(tb[TCA_GACT_PARMS]);
+ index = parm->index;
#ifndef CONFIG_GACT_PROB
if (tb[TCA_GACT_PROB] != NULL)
@@ -91,12 +93,12 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
}
#endif
- err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
if (!err) {
- ret = tcf_idr_create(tn, parm->index, est, a,
+ ret = tcf_idr_create(tn, index, est, a,
&act_gact_ops, bind, true);
if (ret) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return ret;
}
ret = ACT_P_CREATED;
diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c
index 06a3d48..24047e0 100644
--- a/net/sched/act_ife.c
+++ b/net/sched/act_ife.c
@@ -482,8 +482,14 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
u8 *saddr = NULL;
bool exists = false;
int ret = 0;
+ u32 index;
int err;
+ if (!nla) {
+ NL_SET_ERR_MSG_MOD(extack, "IFE requires attributes to be passed");
+ return -EINVAL;
+ }
+
err = nla_parse_nested(tb, TCA_IFE_MAX, nla, ife_policy, NULL);
if (err < 0)
return err;
@@ -504,7 +510,8 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
if (!p)
return -ENOMEM;
- err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ index = parm->index;
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
if (err < 0) {
kfree(p);
return err;
@@ -516,10 +523,10 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
}
if (!exists) {
- ret = tcf_idr_create(tn, parm->index, est, a, &act_ife_ops,
+ ret = tcf_idr_create(tn, index, est, a, &act_ife_ops,
bind, true);
if (ret) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
kfree(p);
return ret;
}
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index f767e78..548614b 100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c
@@ -104,6 +104,7 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
struct net_device *dev;
bool exists = false;
int ret, err;
+ u32 index;
if (!nla) {
NL_SET_ERR_MSG_MOD(extack, "Mirred requires attributes to be passed");
@@ -117,8 +118,8 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
return -EINVAL;
}
parm = nla_data(tb[TCA_MIRRED_PARMS]);
-
- err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ index = parm->index;
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
if (err < 0)
return err;
exists = err;
@@ -135,21 +136,21 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
if (exists)
tcf_idr_release(*a, bind);
else
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
NL_SET_ERR_MSG_MOD(extack, "Unknown mirred option");
return -EINVAL;
}
if (!exists) {
if (!parm->ifindex) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
NL_SET_ERR_MSG_MOD(extack, "Specified device does not exist");
return -EINVAL;
}
- ret = tcf_idr_create(tn, parm->index, est, a,
+ ret = tcf_idr_create(tn, index, est, a,
&act_mirred_ops, bind, true);
if (ret) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return ret;
}
ret = ACT_P_CREATED;
diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c
index 4313aa1..6198289 100644
--- a/net/sched/act_nat.c
+++ b/net/sched/act_nat.c
@@ -45,6 +45,7 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
struct tc_nat *parm;
int ret = 0, err;
struct tcf_nat *p;
+ u32 index;
if (nla == NULL)
return -EINVAL;
@@ -56,13 +57,13 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
if (tb[TCA_NAT_PARMS] == NULL)
return -EINVAL;
parm = nla_data(tb[TCA_NAT_PARMS]);
-
- err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ index = parm->index;
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
if (!err) {
- ret = tcf_idr_create(tn, parm->index, est, a,
+ ret = tcf_idr_create(tn, index, est, a,
&act_nat_ops, bind, false);
if (ret) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return ret;
}
ret = ACT_P_CREATED;
diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c
index ca535a8..82d258b 100644
--- a/net/sched/act_pedit.c
+++ b/net/sched/act_pedit.c
@@ -149,6 +149,7 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
struct tcf_pedit *p;
int ret = 0, err;
int ksize;
+ u32 index;
if (!nla) {
NL_SET_ERR_MSG_MOD(extack, "Pedit requires attributes to be passed");
@@ -178,18 +179,19 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
if (IS_ERR(keys_ex))
return PTR_ERR(keys_ex);
- err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ index = parm->index;
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
if (!err) {
if (!parm->nkeys) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
NL_SET_ERR_MSG_MOD(extack, "Pedit requires keys to be passed");
ret = -EINVAL;
goto out_free;
}
- ret = tcf_idr_create(tn, parm->index, est, a,
+ ret = tcf_idr_create(tn, index, est, a,
&act_pedit_ops, bind, false);
if (ret) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
goto out_free;
}
ret = ACT_P_CREATED;
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index 5d8bfa8..997c34d 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -85,6 +85,7 @@ static int tcf_police_init(struct net *net, struct nlattr *nla,
struct qdisc_rate_table *R_tab = NULL, *P_tab = NULL;
struct tc_action_net *tn = net_generic(net, police_net_id);
bool exists = false;
+ u32 index;
int size;
if (nla == NULL)
@@ -101,7 +102,8 @@ static int tcf_police_init(struct net *net, struct nlattr *nla,
return -EINVAL;
parm = nla_data(tb[TCA_POLICE_TBF]);
- err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ index = parm->index;
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
if (err < 0)
return err;
exists = err;
@@ -109,10 +111,10 @@ static int tcf_police_init(struct net *net, struct nlattr *nla,
return 0;
if (!exists) {
- ret = tcf_idr_create(tn, parm->index, NULL, a,
+ ret = tcf_idr_create(tn, index, NULL, a,
&act_police_ops, bind, false);
if (ret) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return ret;
}
ret = ACT_P_CREATED;
diff --git a/net/sched/act_sample.c b/net/sched/act_sample.c
index c7f5d63..ac37654 100644
--- a/net/sched/act_sample.c
+++ b/net/sched/act_sample.c
@@ -43,7 +43,7 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla,
struct tc_action_net *tn = net_generic(net, sample_net_id);
struct nlattr *tb[TCA_SAMPLE_MAX + 1];
struct psample_group *psample_group;
- u32 psample_group_num, rate;
+ u32 psample_group_num, rate, index;
struct tc_sample *parm;
struct tcf_sample *s;
bool exists = false;
@@ -59,8 +59,8 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla,
return -EINVAL;
parm = nla_data(tb[TCA_SAMPLE_PARMS]);
-
- err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ index = parm->index;
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
if (err < 0)
return err;
exists = err;
@@ -68,10 +68,10 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla,
return 0;
if (!exists) {
- ret = tcf_idr_create(tn, parm->index, est, a,
+ ret = tcf_idr_create(tn, index, est, a,
&act_sample_ops, bind, true);
if (ret) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return ret;
}
ret = ACT_P_CREATED;
diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c
index 52400d4..658efae 100644
--- a/net/sched/act_simple.c
+++ b/net/sched/act_simple.c
@@ -88,6 +88,7 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla,
struct tcf_defact *d;
bool exists = false;
int ret = 0, err;
+ u32 index;
if (nla == NULL)
return -EINVAL;
@@ -100,7 +101,8 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla,
return -EINVAL;
parm = nla_data(tb[TCA_DEF_PARMS]);
- err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ index = parm->index;
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
if (err < 0)
return err;
exists = err;
@@ -111,15 +113,15 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla,
if (exists)
tcf_idr_release(*a, bind);
else
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return -EINVAL;
}
if (!exists) {
- ret = tcf_idr_create(tn, parm->index, est, a,
+ ret = tcf_idr_create(tn, index, est, a,
&act_simp_ops, bind, false);
if (ret) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return ret;
}
diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c
index 86d90fc..7709710 100644
--- a/net/sched/act_skbedit.c
+++ b/net/sched/act_skbedit.c
@@ -107,6 +107,7 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
u16 *queue_mapping = NULL, *ptype = NULL;
bool exists = false;
int ret = 0, err;
+ u32 index;
if (nla == NULL)
return -EINVAL;
@@ -153,8 +154,8 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
}
parm = nla_data(tb[TCA_SKBEDIT_PARMS]);
-
- err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ index = parm->index;
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
if (err < 0)
return err;
exists = err;
@@ -165,15 +166,15 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
if (exists)
tcf_idr_release(*a, bind);
else
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return -EINVAL;
}
if (!exists) {
- ret = tcf_idr_create(tn, parm->index, est, a,
+ ret = tcf_idr_create(tn, index, est, a,
&act_skbedit_ops, bind, true);
if (ret) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return ret;
}
diff --git a/net/sched/act_skbmod.c b/net/sched/act_skbmod.c
index 588077f..3038493 100644
--- a/net/sched/act_skbmod.c
+++ b/net/sched/act_skbmod.c
@@ -88,12 +88,12 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla,
struct nlattr *tb[TCA_SKBMOD_MAX + 1];
struct tcf_skbmod_params *p, *p_old;
struct tc_skbmod *parm;
+ u32 lflags = 0, index;
struct tcf_skbmod *d;
bool exists = false;
u8 *daddr = NULL;
u8 *saddr = NULL;
u16 eth_type = 0;
- u32 lflags = 0;
int ret = 0, err;
if (!nla)
@@ -122,10 +122,11 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla,
}
parm = nla_data(tb[TCA_SKBMOD_PARMS]);
+ index = parm->index;
if (parm->flags & SKBMOD_F_SWAPMAC)
lflags = SKBMOD_F_SWAPMAC;
- err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
if (err < 0)
return err;
exists = err;
@@ -136,15 +137,15 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla,
if (exists)
tcf_idr_release(*a, bind);
else
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return -EINVAL;
}
if (!exists) {
- ret = tcf_idr_create(tn, parm->index, est, a,
+ ret = tcf_idr_create(tn, index, est, a,
&act_skbmod_ops, bind, true);
if (ret) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return ret;
}
diff --git a/net/sched/act_tunnel_key.c b/net/sched/act_tunnel_key.c
index 72d9c43..66bfe57 100644
--- a/net/sched/act_tunnel_key.c
+++ b/net/sched/act_tunnel_key.c
@@ -224,6 +224,7 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla,
__be16 flags;
u8 tos, ttl;
int ret = 0;
+ u32 index;
int err;
if (!nla) {
@@ -244,7 +245,8 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla,
}
parm = nla_data(tb[TCA_TUNNEL_KEY_PARMS]);
- err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ index = parm->index;
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
if (err < 0)
return err;
exists = err;
@@ -338,7 +340,7 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla,
}
if (!exists) {
- ret = tcf_idr_create(tn, parm->index, est, a,
+ ret = tcf_idr_create(tn, index, est, a,
&act_tunnel_key_ops, bind, true);
if (ret) {
NL_SET_ERR_MSG(extack, "Cannot create TC IDR");
@@ -384,7 +386,7 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla,
if (exists)
tcf_idr_release(*a, bind);
else
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return ret;
}
diff --git a/net/sched/act_vlan.c b/net/sched/act_vlan.c
index 033d273..da993edd 100644
--- a/net/sched/act_vlan.c
+++ b/net/sched/act_vlan.c
@@ -118,6 +118,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
u8 push_prio = 0;
bool exists = false;
int ret = 0, err;
+ u32 index;
if (!nla)
return -EINVAL;
@@ -129,7 +130,8 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
if (!tb[TCA_VLAN_PARMS])
return -EINVAL;
parm = nla_data(tb[TCA_VLAN_PARMS]);
- err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
+ index = parm->index;
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
if (err < 0)
return err;
exists = err;
@@ -145,7 +147,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
if (exists)
tcf_idr_release(*a, bind);
else
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return -EINVAL;
}
push_vid = nla_get_u16(tb[TCA_VLAN_PUSH_VLAN_ID]);
@@ -153,7 +155,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
if (exists)
tcf_idr_release(*a, bind);
else
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return -ERANGE;
}
@@ -167,7 +169,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
if (exists)
tcf_idr_release(*a, bind);
else
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return -EPROTONOSUPPORT;
}
} else {
@@ -181,16 +183,16 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
if (exists)
tcf_idr_release(*a, bind);
else
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return -EINVAL;
}
action = parm->v_action;
if (!exists) {
- ret = tcf_idr_create(tn, parm->index, est, a,
+ ret = tcf_idr_create(tn, index, est, a,
&act_vlan_ops, bind, true);
if (ret) {
- tcf_idr_cleanup(tn, parm->index);
+ tcf_idr_cleanup(tn, index);
return ret;
}
@@ -296,6 +298,14 @@ static int tcf_vlan_search(struct net *net, struct tc_action **a, u32 index,
return tcf_idr_search(tn, a, index);
}
+static size_t tcf_vlan_get_fill_size(const struct tc_action *act)
+{
+ return nla_total_size(sizeof(struct tc_vlan))
+ + nla_total_size(sizeof(u16)) /* TCA_VLAN_PUSH_VLAN_ID */
+ + nla_total_size(sizeof(u16)) /* TCA_VLAN_PUSH_VLAN_PROTOCOL */
+ + nla_total_size(sizeof(u8)); /* TCA_VLAN_PUSH_VLAN_PRIORITY */
+}
+
static struct tc_action_ops act_vlan_ops = {
.kind = "vlan",
.type = TCA_ACT_VLAN,
@@ -305,6 +315,7 @@ static struct tc_action_ops act_vlan_ops = {
.init = tcf_vlan_init,
.cleanup = tcf_vlan_cleanup,
.walk = tcf_vlan_walker,
+ .get_fill_size = tcf_vlan_get_fill_size,
.lookup = tcf_vlan_search,
.size = sizeof(struct tcf_vlan),
};
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 2167c6c..4159bcb 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -1325,6 +1325,9 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
tcf_chain_tp_insert(chain, &chain_info, tp);
tfilter_notify(net, skb, n, tp, block, q, parent, fh,
RTM_NEWTFILTER, false);
+ /* q pointer is NULL for shared blocks */
+ if (q)
+ q->flags &= ~TCQ_F_CAN_BYPASS;
} else {
if (tp_created)
tcf_proto_destroy(tp, NULL);
diff --git a/net/sched/sch_codel.c b/net/sched/sch_codel.c
index 17cd81f..77fae0b 100644
--- a/net/sched/sch_codel.c
+++ b/net/sched/sch_codel.c
@@ -71,10 +71,10 @@ static struct sk_buff *dequeue_func(struct codel_vars *vars, void *ctx)
struct Qdisc *sch = ctx;
struct sk_buff *skb = __qdisc_dequeue_head(&sch->q);
- if (skb)
+ if (skb) {
sch->qstats.backlog -= qdisc_pkt_len(skb);
-
- prefetch(&skb->end); /* we'll need skb_shinfo() */
+ prefetch(&skb->end); /* we'll need skb_shinfo() */
+ }
return skb;
}
diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c
index 6c0a9d5..137692c 100644
--- a/net/sched/sch_fq_codel.c
+++ b/net/sched/sch_fq_codel.c
@@ -600,8 +600,6 @@ static unsigned long fq_codel_find(struct Qdisc *sch, u32 classid)
static unsigned long fq_codel_bind(struct Qdisc *sch, unsigned long parent,
u32 classid)
{
- /* we cannot bypass queue discipline anymore */
- sch->flags &= ~TCQ_F_CAN_BYPASS;
return 0;
}
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 2f26781..650f214 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -828,8 +828,6 @@ static unsigned long sfq_find(struct Qdisc *sch, u32 classid)
static unsigned long sfq_bind(struct Qdisc *sch, unsigned long parent,
u32 classid)
{
- /* we cannot bypass queue discipline anymore */
- sch->flags &= ~TCQ_F_CAN_BYPASS;
return 0;
}
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 8c00a7e..9f5b4e5 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -4507,34 +4507,18 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
static int sctp_connect(struct sock *sk, struct sockaddr *addr,
int addr_len, int flags)
{
- struct inet_sock *inet = inet_sk(sk);
struct sctp_af *af;
- int err = 0;
+ int err = -EINVAL;
lock_sock(sk);
pr_debug("%s: sk:%p, sockaddr:%p, addr_len:%d\n", __func__, sk,
addr, addr_len);
- /* We may need to bind the socket. */
- if (!inet->inet_num) {
- if (sk->sk_prot->get_port(sk, 0)) {
- release_sock(sk);
- return -EAGAIN;
- }
- inet->inet_sport = htons(inet->inet_num);
- }
-
/* Validate addr_len before calling common connect/connectx routine. */
af = sctp_get_af_specific(addr->sa_family);
- if (!af || addr_len < af->sockaddr_len) {
- err = -EINVAL;
- } else {
- /* Pass correct addr len to common routine (so it knows there
- * is only one address being passed.
- */
+ if (af && addr_len >= af->sockaddr_len)
err = __sctp_connect(sk, addr, af->sockaddr_len, flags, NULL);
- }
release_sock(sk);
return err;
diff --git a/net/sctp/stream.c b/net/sctp/stream.c
index 3b47457..0da5793 100644
--- a/net/sctp/stream.c
+++ b/net/sctp/stream.c
@@ -253,13 +253,20 @@ int sctp_stream_init(struct sctp_stream *stream, __u16 outcnt, __u16 incnt,
int sctp_stream_init_ext(struct sctp_stream *stream, __u16 sid)
{
struct sctp_stream_out_ext *soute;
+ int ret;
soute = kzalloc(sizeof(*soute), GFP_KERNEL);
if (!soute)
return -ENOMEM;
SCTP_SO(stream, sid)->ext = soute;
- return sctp_sched_init_sid(stream, sid, GFP_KERNEL);
+ ret = sctp_sched_init_sid(stream, sid, GFP_KERNEL);
+ if (ret) {
+ kfree(SCTP_SO(stream, sid)->ext);
+ SCTP_SO(stream, sid)->ext = NULL;
+ }
+
+ return ret;
}
void sctp_stream_free(struct sctp_stream *stream)
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
index 9bbab6b..26dcd02 100644
--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c
@@ -1680,14 +1680,18 @@ static int smc_setsockopt(struct socket *sock, int level, int optname,
}
break;
case TCP_NODELAY:
- if (sk->sk_state != SMC_INIT && sk->sk_state != SMC_LISTEN) {
+ if (sk->sk_state != SMC_INIT &&
+ sk->sk_state != SMC_LISTEN &&
+ sk->sk_state != SMC_CLOSED) {
if (val && !smc->use_fallback)
mod_delayed_work(system_wq, &smc->conn.tx_work,
0);
}
break;
case TCP_CORK:
- if (sk->sk_state != SMC_INIT && sk->sk_state != SMC_LISTEN) {
+ if (sk->sk_state != SMC_INIT &&
+ sk->sk_state != SMC_LISTEN &&
+ sk->sk_state != SMC_CLOSED) {
if (!val && !smc->use_fallback)
mod_delayed_work(system_wq, &smc->conn.tx_work,
0);
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 7e4553d..0d7d149 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -2713,6 +2713,7 @@ int rpc_clnt_add_xprt(struct rpc_clnt *clnt,
xprt = xprt_iter_xprt(&clnt->cl_xpi);
if (xps == NULL || xprt == NULL) {
rcu_read_unlock();
+ xprt_switch_put(xps);
return -EAGAIN;
}
resvport = xprt->resvport;
diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c
index 85ebb67..318c541 100644
--- a/net/tipc/netlink_compat.c
+++ b/net/tipc/netlink_compat.c
@@ -55,6 +55,7 @@ struct tipc_nl_compat_msg {
int rep_type;
int rep_size;
int req_type;
+ int req_size;
struct net *net;
struct sk_buff *rep;
struct tlv_desc *req;
@@ -257,7 +258,8 @@ static int tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd,
int err;
struct sk_buff *arg;
- if (msg->req_type && !TLV_CHECK_TYPE(msg->req, msg->req_type))
+ if (msg->req_type && (!msg->req_size ||
+ !TLV_CHECK_TYPE(msg->req, msg->req_type)))
return -EINVAL;
msg->rep = tipc_tlv_alloc(msg->rep_size);
@@ -354,7 +356,8 @@ static int tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd,
{
int err;
- if (msg->req_type && !TLV_CHECK_TYPE(msg->req, msg->req_type))
+ if (msg->req_type && (!msg->req_size ||
+ !TLV_CHECK_TYPE(msg->req, msg->req_type)))
return -EINVAL;
err = __tipc_nl_compat_doit(cmd, msg);
@@ -1276,8 +1279,8 @@ static int tipc_nl_compat_recv(struct sk_buff *skb, struct genl_info *info)
goto send;
}
- len = nlmsg_attrlen(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN);
- if (!len || !TLV_OK(msg.req, len)) {
+ msg.req_size = nlmsg_attrlen(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN);
+ if (msg.req_size && !TLV_OK(msg.req, msg.req_size)) {
msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_SUPPORTED);
err = -EOPNOTSUPP;
goto send;
diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c
index ead29c2..0a613e0 100644
--- a/net/tls/tls_device.c
+++ b/net/tls/tls_device.c
@@ -61,7 +61,7 @@ static void tls_device_free_ctx(struct tls_context *ctx)
if (ctx->rx_conf == TLS_HW)
kfree(tls_offload_ctx_rx(ctx));
- kfree(ctx);
+ tls_ctx_free(ctx);
}
static void tls_device_gc_task(struct work_struct *work)
diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
index 25b3fb58..4c0ac79 100644
--- a/net/tls/tls_main.c
+++ b/net/tls/tls_main.c
@@ -241,7 +241,7 @@ static void tls_write_space(struct sock *sk)
ctx->sk_write_space(sk);
}
-static void tls_ctx_free(struct tls_context *ctx)
+void tls_ctx_free(struct tls_context *ctx)
{
if (!ctx)
return;
diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
index ab27a28..2e30bf1 100644
--- a/net/vmw_vsock/af_vsock.c
+++ b/net/vmw_vsock/af_vsock.c
@@ -281,7 +281,8 @@ EXPORT_SYMBOL_GPL(vsock_insert_connected);
void vsock_remove_bound(struct vsock_sock *vsk)
{
spin_lock_bh(&vsock_table_lock);
- __vsock_remove_bound(vsk);
+ if (__vsock_in_bound_table(vsk))
+ __vsock_remove_bound(vsk);
spin_unlock_bh(&vsock_table_lock);
}
EXPORT_SYMBOL_GPL(vsock_remove_bound);
@@ -289,7 +290,8 @@ EXPORT_SYMBOL_GPL(vsock_remove_bound);
void vsock_remove_connected(struct vsock_sock *vsk)
{
spin_lock_bh(&vsock_table_lock);
- __vsock_remove_connected(vsk);
+ if (__vsock_in_connected_table(vsk))
+ __vsock_remove_connected(vsk);
spin_unlock_bh(&vsock_table_lock);
}
EXPORT_SYMBOL_GPL(vsock_remove_connected);
@@ -325,35 +327,10 @@ struct sock *vsock_find_connected_socket(struct sockaddr_vm *src,
}
EXPORT_SYMBOL_GPL(vsock_find_connected_socket);
-static bool vsock_in_bound_table(struct vsock_sock *vsk)
-{
- bool ret;
-
- spin_lock_bh(&vsock_table_lock);
- ret = __vsock_in_bound_table(vsk);
- spin_unlock_bh(&vsock_table_lock);
-
- return ret;
-}
-
-static bool vsock_in_connected_table(struct vsock_sock *vsk)
-{
- bool ret;
-
- spin_lock_bh(&vsock_table_lock);
- ret = __vsock_in_connected_table(vsk);
- spin_unlock_bh(&vsock_table_lock);
-
- return ret;
-}
-
void vsock_remove_sock(struct vsock_sock *vsk)
{
- if (vsock_in_bound_table(vsk))
- vsock_remove_bound(vsk);
-
- if (vsock_in_connected_table(vsk))
- vsock_remove_connected(vsk);
+ vsock_remove_bound(vsk);
+ vsock_remove_connected(vsk);
}
EXPORT_SYMBOL_GPL(vsock_remove_sock);
@@ -484,8 +461,7 @@ static void vsock_pending_work(struct work_struct *work)
* incoming packets can't find this socket, and to reduce the reference
* count.
*/
- if (vsock_in_connected_table(vsk))
- vsock_remove_connected(vsk);
+ vsock_remove_connected(vsk);
sk->sk_state = TCP_CLOSE;
diff --git a/net/vmw_vsock/hyperv_transport.c b/net/vmw_vsock/hyperv_transport.c
index a827547..9c7da81 100644
--- a/net/vmw_vsock/hyperv_transport.c
+++ b/net/vmw_vsock/hyperv_transport.c
@@ -35,6 +35,9 @@
/* The MTU is 16KB per the host side's design */
#define HVS_MTU_SIZE (1024 * 16)
+/* How long to wait for graceful shutdown of a connection */
+#define HVS_CLOSE_TIMEOUT (8 * HZ)
+
struct vmpipe_proto_header {
u32 pkt_type;
u32 data_size;
@@ -217,18 +220,6 @@ static void hvs_set_channel_pending_send_size(struct vmbus_channel *chan)
set_channel_pending_send_size(chan,
HVS_PKT_LEN(HVS_SEND_BUF_SIZE));
- /* See hvs_stream_has_space(): we must make sure the host has seen
- * the new pending send size, before we can re-check the writable
- * bytes.
- */
- virt_mb();
-}
-
-static void hvs_clear_channel_pending_send_size(struct vmbus_channel *chan)
-{
- set_channel_pending_send_size(chan, 0);
-
- /* Ditto */
virt_mb();
}
@@ -298,26 +289,36 @@ static void hvs_channel_cb(void *ctx)
if (hvs_channel_readable(chan))
sk->sk_data_ready(sk);
- /* See hvs_stream_has_space(): when we reach here, the writable bytes
- * may be already less than HVS_PKT_LEN(HVS_SEND_BUF_SIZE).
- */
if (hv_get_bytes_to_write(&chan->outbound) > 0)
sk->sk_write_space(sk);
}
+static void hvs_do_close_lock_held(struct vsock_sock *vsk,
+ bool cancel_timeout)
+{
+ struct sock *sk = sk_vsock(vsk);
+
+ sock_set_flag(sk, SOCK_DONE);
+ vsk->peer_shutdown = SHUTDOWN_MASK;
+ if (vsock_stream_has_data(vsk) <= 0)
+ sk->sk_state = TCP_CLOSING;
+ sk->sk_state_change(sk);
+ if (vsk->close_work_scheduled &&
+ (!cancel_timeout || cancel_delayed_work(&vsk->close_work))) {
+ vsk->close_work_scheduled = false;
+ vsock_remove_sock(vsk);
+
+ /* Release the reference taken while scheduling the timeout */
+ sock_put(sk);
+ }
+}
+
static void hvs_close_connection(struct vmbus_channel *chan)
{
struct sock *sk = get_per_channel_state(chan);
- struct vsock_sock *vsk = vsock_sk(sk);
lock_sock(sk);
-
- sk->sk_state = TCP_CLOSE;
- sock_set_flag(sk, SOCK_DONE);
- vsk->peer_shutdown |= SEND_SHUTDOWN | RCV_SHUTDOWN;
-
- sk->sk_state_change(sk);
-
+ hvs_do_close_lock_held(vsock_sk(sk), true);
release_sock(sk);
}
@@ -328,8 +329,9 @@ static void hvs_open_connection(struct vmbus_channel *chan)
struct sockaddr_vm addr;
struct sock *sk, *new = NULL;
- struct vsock_sock *vnew;
- struct hvsock *hvs, *hvs_new;
+ struct vsock_sock *vnew = NULL;
+ struct hvsock *hvs = NULL;
+ struct hvsock *hvs_new = NULL;
int ret;
if_type = &chan->offermsg.offer.if_type;
@@ -388,6 +390,13 @@ static void hvs_open_connection(struct vmbus_channel *chan)
set_per_channel_state(chan, conn_from_host ? new : sk);
vmbus_set_chn_rescind_callback(chan, hvs_close_connection);
+ /* Set the pending send size to max packet size to always get
+ * notifications from the host when there is enough writable space.
+ * The host is optimized to send notifications only when the pending
+ * size boundary is crossed, and not always.
+ */
+ hvs_set_channel_pending_send_size(chan);
+
if (conn_from_host) {
new->sk_state = TCP_ESTABLISHED;
sk->sk_ack_backlog++;
@@ -452,50 +461,80 @@ static int hvs_connect(struct vsock_sock *vsk)
return vmbus_send_tl_connect_request(&h->vm_srv_id, &h->host_srv_id);
}
+static void hvs_shutdown_lock_held(struct hvsock *hvs, int mode)
+{
+ struct vmpipe_proto_header hdr;
+
+ if (hvs->fin_sent || !hvs->chan)
+ return;
+
+ /* It can't fail: see hvs_channel_writable_bytes(). */
+ (void)hvs_send_data(hvs->chan, (struct hvs_send_buf *)&hdr, 0);
+ hvs->fin_sent = true;
+}
+
static int hvs_shutdown(struct vsock_sock *vsk, int mode)
{
struct sock *sk = sk_vsock(vsk);
- struct vmpipe_proto_header hdr;
- struct hvs_send_buf *send_buf;
- struct hvsock *hvs;
if (!(mode & SEND_SHUTDOWN))
return 0;
lock_sock(sk);
-
- hvs = vsk->trans;
- if (hvs->fin_sent)
- goto out;
-
- send_buf = (struct hvs_send_buf *)&hdr;
-
- /* It can't fail: see hvs_channel_writable_bytes(). */
- (void)hvs_send_data(hvs->chan, send_buf, 0);
-
- hvs->fin_sent = true;
-out:
+ hvs_shutdown_lock_held(vsk->trans, mode);
release_sock(sk);
return 0;
}
+static void hvs_close_timeout(struct work_struct *work)
+{
+ struct vsock_sock *vsk =
+ container_of(work, struct vsock_sock, close_work.work);
+ struct sock *sk = sk_vsock(vsk);
+
+ sock_hold(sk);
+ lock_sock(sk);
+ if (!sock_flag(sk, SOCK_DONE))
+ hvs_do_close_lock_held(vsk, false);
+
+ vsk->close_work_scheduled = false;
+ release_sock(sk);
+ sock_put(sk);
+}
+
+/* Returns true, if it is safe to remove socket; false otherwise */
+static bool hvs_close_lock_held(struct vsock_sock *vsk)
+{
+ struct sock *sk = sk_vsock(vsk);
+
+ if (!(sk->sk_state == TCP_ESTABLISHED ||
+ sk->sk_state == TCP_CLOSING))
+ return true;
+
+ if ((sk->sk_shutdown & SHUTDOWN_MASK) != SHUTDOWN_MASK)
+ hvs_shutdown_lock_held(vsk->trans, SHUTDOWN_MASK);
+
+ if (sock_flag(sk, SOCK_DONE))
+ return true;
+
+ /* This reference will be dropped by the delayed close routine */
+ sock_hold(sk);
+ INIT_DELAYED_WORK(&vsk->close_work, hvs_close_timeout);
+ vsk->close_work_scheduled = true;
+ schedule_delayed_work(&vsk->close_work, HVS_CLOSE_TIMEOUT);
+ return false;
+}
+
static void hvs_release(struct vsock_sock *vsk)
{
struct sock *sk = sk_vsock(vsk);
- struct hvsock *hvs = vsk->trans;
- struct vmbus_channel *chan;
+ bool remove_sock;
lock_sock(sk);
-
- sk->sk_state = TCP_CLOSING;
- vsock_remove_sock(vsk);
-
+ remove_sock = hvs_close_lock_held(vsk);
release_sock(sk);
-
- chan = hvs->chan;
- if (chan)
- hvs_shutdown(vsk, RCV_SHUTDOWN | SEND_SHUTDOWN);
-
+ if (remove_sock)
+ vsock_remove_sock(vsk);
}
static void hvs_destruct(struct vsock_sock *vsk)
@@ -651,23 +690,8 @@ static s64 hvs_stream_has_data(struct vsock_sock *vsk)
static s64 hvs_stream_has_space(struct vsock_sock *vsk)
{
struct hvsock *hvs = vsk->trans;
- struct vmbus_channel *chan = hvs->chan;
- s64 ret;
- ret = hvs_channel_writable_bytes(chan);
- if (ret > 0) {
- hvs_clear_channel_pending_send_size(chan);
- } else {
- /* See hvs_channel_cb() */
- hvs_set_channel_pending_send_size(chan);
-
- /* Re-check the writable bytes to avoid race */
- ret = hvs_channel_writable_bytes(chan);
- if (ret > 0)
- hvs_clear_channel_pending_send_size(chan);
- }
-
- return ret;
+ return hvs_channel_writable_bytes(hvs->chan);
}
static u64 hvs_stream_rcvhiwat(struct vsock_sock *vsk)
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 2821b3e..83a1781 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1219,7 +1219,7 @@ static u32 cfg80211_calculate_bitrate_he(struct rate_info *rate)
if (rate->he_dcm)
result /= 2;
- return result;
+ return result / 10000;
}
u32 cfg80211_calculate_bitrate(struct rate_info *rate)
diff --git a/net/xdp/xsk_queue.h b/net/xdp/xsk_queue.h
index 8a64b15..fe96c0d 100644
--- a/net/xdp/xsk_queue.h
+++ b/net/xdp/xsk_queue.h
@@ -239,7 +239,7 @@ static inline void xskq_produce_flush_desc(struct xsk_queue *q)
/* Order producer and data */
smp_wmb();
- q->prod_tail = q->prod_head,
+ q->prod_tail = q->prod_head;
WRITE_ONCE(q->ring->producer, q->prod_tail);
}
diff --git a/net/xfrm/Kconfig b/net/xfrm/Kconfig
index 4a9ee2d..372c91fa 100644
--- a/net/xfrm/Kconfig
+++ b/net/xfrm/Kconfig
@@ -14,6 +14,8 @@
tristate
select XFRM
select CRYPTO
+ select CRYPTO_HASH
+ select CRYPTO_BLKCIPHER
config XFRM_USER
tristate "Transformation user configuration interface"
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 11e09eb..f08ab5c 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -2091,11 +2091,6 @@ int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen
struct xfrm_mgr *km;
struct xfrm_policy *pol = NULL;
-#ifdef CONFIG_COMPAT
- if (in_compat_syscall())
- return -EOPNOTSUPP;
-#endif
-
if (!optval && !optlen) {
xfrm_sk_policy_insert(sk, XFRM_POLICY_IN, NULL);
xfrm_sk_policy_insert(sk, XFRM_POLICY_OUT, NULL);
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 2122f89..1bb6992 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -151,6 +151,25 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
err = -EINVAL;
switch (p->family) {
case AF_INET:
+ break;
+
+ case AF_INET6:
+#if IS_ENABLED(CONFIG_IPV6)
+ break;
+#else
+ err = -EAFNOSUPPORT;
+ goto out;
+#endif
+
+ default:
+ goto out;
+ }
+
+ switch (p->sel.family) {
+ case AF_UNSPEC:
+ break;
+
+ case AF_INET:
if (p->sel.prefixlen_d > 32 || p->sel.prefixlen_s > 32)
goto out;
@@ -2614,11 +2633,6 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
const struct xfrm_link *link;
int type, err;
-#ifdef CONFIG_COMPAT
- if (in_compat_syscall())
- return -EOPNOTSUPP;
-#endif
-
type = nlh->nlmsg_type;
if (type > XFRM_MSG_MAX)
return -EINVAL;
diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c
index cf40a82..5061a2e 100644
--- a/samples/bpf/bpf_load.c
+++ b/samples/bpf/bpf_load.c
@@ -677,7 +677,7 @@ void read_trace_pipe(void)
static char buf[4096];
ssize_t sz;
- sz = read(trace_fd, buf, sizeof(buf));
+ sz = read(trace_fd, buf, sizeof(buf) - 1);
if (sz > 0) {
buf[sz] = 0;
puts(buf);
diff --git a/samples/bpf/task_fd_query_user.c b/samples/bpf/task_fd_query_user.c
index 8381d79..06957f0 100644
--- a/samples/bpf/task_fd_query_user.c
+++ b/samples/bpf/task_fd_query_user.c
@@ -216,7 +216,7 @@ static int test_debug_fs_uprobe(char *binary_path, long offset, bool is_return)
{
const char *event_type = "uprobe";
struct perf_event_attr attr = {};
- char buf[256], event_alias[256];
+ char buf[256], event_alias[sizeof("test_1234567890")];
__u64 probe_offset, probe_addr;
__u32 len, prog_id, fd_type;
int err, res, kfd, efd;
diff --git a/scripts/genksyms/keywords.c b/scripts/genksyms/keywords.c
index 9f40bcd..f6956aa 100644
--- a/scripts/genksyms/keywords.c
+++ b/scripts/genksyms/keywords.c
@@ -24,6 +24,10 @@
{ "__volatile__", VOLATILE_KEYW },
{ "__builtin_va_list", VA_LIST_KEYW },
+ { "__int128", BUILTIN_INT_KEYW },
+ { "__int128_t", BUILTIN_INT_KEYW },
+ { "__uint128_t", BUILTIN_INT_KEYW },
+
// According to rth, c99 defines "_Bool", __restrict", __restrict__", "restrict". KAO
{ "_Bool", BOOL_KEYW },
{ "_restrict", RESTRICT_KEYW },
diff --git a/scripts/genksyms/parse.y b/scripts/genksyms/parse.y
index 00a6d7e..1ebcf52 100644
--- a/scripts/genksyms/parse.y
+++ b/scripts/genksyms/parse.y
@@ -76,6 +76,7 @@
%token ATTRIBUTE_KEYW
%token AUTO_KEYW
%token BOOL_KEYW
+%token BUILTIN_INT_KEYW
%token CHAR_KEYW
%token CONST_KEYW
%token DOUBLE_KEYW
@@ -263,6 +264,7 @@
| VOID_KEYW
| BOOL_KEYW
| VA_LIST_KEYW
+ | BUILTIN_INT_KEYW
| TYPE { (*$1)->tag = SYM_TYPEDEF; $$ = $1; }
;
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 0c9c54b..31ed7f3 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -152,6 +152,9 @@ static int read_symbol(FILE *in, struct sym_entry *s)
/* exclude debugging symbols */
else if (stype == 'N' || stype == 'n')
return -1;
+ /* exclude s390 kasan local symbols */
+ else if (!strncmp(sym, ".LASANPC", 8))
+ return -1;
/* include the type field in the symbol name, so that it gets
* compressed together */
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
index 91d0a5c..0dde19c 100644
--- a/scripts/kconfig/confdata.c
+++ b/scripts/kconfig/confdata.c
@@ -784,6 +784,7 @@ int conf_write(const char *name)
const char *str;
char dirname[PATH_MAX+1], tmpname[PATH_MAX+22], newname[PATH_MAX+8];
char *env;
+ int i;
dirname[0] = 0;
if (name && name[0]) {
@@ -834,11 +835,12 @@ int conf_write(const char *name)
"#\n"
"# %s\n"
"#\n", str);
- } else if (!(sym->flags & SYMBOL_CHOICE)) {
+ } else if (!(sym->flags & SYMBOL_CHOICE) &&
+ !(sym->flags & SYMBOL_WRITTEN)) {
sym_calc_value(sym);
if (!(sym->flags & SYMBOL_WRITE))
goto next;
- sym->flags &= ~SYMBOL_WRITE;
+ sym->flags |= SYMBOL_WRITTEN;
conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
}
@@ -859,6 +861,9 @@ int conf_write(const char *name)
}
fclose(out);
+ for_all_symbols(i, sym)
+ sym->flags &= ~SYMBOL_WRITTEN;
+
if (*tmpname) {
strcat(dirname, basename);
strcat(dirname, ".old");
@@ -1024,8 +1029,6 @@ int conf_write_autoconf(int overwrite)
if (!overwrite && is_present(autoconf_name))
return 0;
- sym_clear_all_valid();
-
conf_write_dep("include/config/auto.conf.cmd");
if (conf_split_config())
diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h
index 7c329e179..43a87f8 100644
--- a/scripts/kconfig/expr.h
+++ b/scripts/kconfig/expr.h
@@ -141,6 +141,7 @@ struct symbol {
#define SYMBOL_OPTIONAL 0x0100 /* choice is optional - values can be 'n' */
#define SYMBOL_WRITE 0x0200 /* write symbol to file (KCONFIG_CONFIG) */
#define SYMBOL_CHANGED 0x0400 /* ? */
+#define SYMBOL_WRITTEN 0x0800 /* track info to avoid double-write to .config */
#define SYMBOL_NO_WRITE 0x1000 /* Symbol for internal use only; it will not be written */
#define SYMBOL_CHECKED 0x2000 /* used during dependency checking */
#define SYMBOL_WARNED 0x8000 /* warning has been issued */
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index 09b9fa7..63fa0cb 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -413,3 +413,14 @@
exit 1
fi
fi
+
+# Starting Android Q, the DTB's are part of dtb.img and not part
+# of the kernel image. RTIC DTS relies on the kernel environment
+# and could not build outside of the kernel. Generate RTIC DTS after
+# successful kernel build if MPGen is enabled. The DTB will be
+# generated with dtb.img in kernel_definitions.mk.
+if [ ! -z ${RTIC_MPGEN+x} ]; then
+ ${RTIC_MPGEN} --objcopy="${OBJCOPY}" --objdump="${OBJDUMP}" \
+ --binpath="" --vmlinux="vmlinux" --config=${KCONFIG_CONFIG} \
+ --cc="${CC} ${KBUILD_AFLAGS}" --dts=rtic_mp.dts
+fi
diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h
index 2e77937..ccfbfde 100644
--- a/scripts/recordmcount.h
+++ b/scripts/recordmcount.h
@@ -326,7 +326,8 @@ static uint_t *sift_rel_mcount(uint_t *mlocp,
if (!mcountsym)
mcountsym = get_mcountsym(sym0, relp, str0);
- if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) {
+ if (mcountsym && mcountsym == Elf_r_sym(relp) &&
+ !is_fake_mcount(relp)) {
uint_t const addend =
_w(_w(relp->r_offset) - recval + mcount_adjust);
mrelp->r_offset = _w(offbase
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 70bad15..109ab51 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6550,11 +6550,12 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
} else if (!strcmp(name, "fscreate")) {
tsec->create_sid = sid;
} else if (!strcmp(name, "keycreate")) {
- error = avc_has_perm(&selinux_state,
- mysid, sid, SECCLASS_KEY, KEY__CREATE,
- NULL);
- if (error)
- goto abort_change;
+ if (sid) {
+ error = avc_has_perm(&selinux_state, mysid, sid,
+ SECCLASS_KEY, KEY__CREATE, NULL);
+ if (error)
+ goto abort_change;
+ }
tsec->keycreate_sid = sid;
} else if (!strcmp(name, "sockcreate")) {
tsec->sockcreate_sid = sid;
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index d31a52e..91d259c 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -275,6 +275,8 @@ static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2)
return v;
}
+static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap);
+
/*
* Initialize a policy database structure.
*/
@@ -322,8 +324,10 @@ static int policydb_init(struct policydb *p)
out:
hashtab_destroy(p->filename_trans);
hashtab_destroy(p->range_tr);
- for (i = 0; i < SYM_NUM; i++)
+ for (i = 0; i < SYM_NUM; i++) {
+ hashtab_map(p->symtab[i].table, destroy_f[i], NULL);
hashtab_destroy(p->symtab[i].table);
+ }
return rc;
}
diff --git a/sound/ac97/bus.c b/sound/ac97/bus.c
index 9cbf692..ca50ff4 100644
--- a/sound/ac97/bus.c
+++ b/sound/ac97/bus.c
@@ -125,17 +125,12 @@ static int ac97_codec_add(struct ac97_controller *ac97_ctrl, int idx,
vendor_id);
ret = device_add(&codec->dev);
- if (ret)
- goto err_free_codec;
+ if (ret) {
+ put_device(&codec->dev);
+ return ret;
+ }
return 0;
-err_free_codec:
- of_node_put(codec->dev.of_node);
- put_device(&codec->dev);
- kfree(codec);
- ac97_ctrl->codecs[idx] = NULL;
-
- return ret;
}
unsigned int snd_ac97_bus_scan_one(struct ac97_controller *adrv,
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index f59e13c..bbf91a5 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -1004,7 +1004,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;
+ int err, handled;
struct snd_seq_event event;
if (!(snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT))
@@ -1017,6 +1017,8 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,
if (!client->accept_output || client->pool == NULL)
return -ENXIO;
+ repeat:
+ handled = 0;
/* 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)) {
@@ -1076,12 +1078,19 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,
0, 0, &client->ioctl_mutex);
if (err < 0)
break;
+ handled++;
__skip_event:
/* Update pointers and counts */
count -= len;
buf += len;
written += len;
+
+ /* let's have a coffee break if too many events are queued */
+ if (++handled >= 200) {
+ mutex_unlock(&client->ioctl_mutex);
+ goto repeat;
+ }
}
out:
diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c
index 27eb027..3847fe8 100644
--- a/sound/hda/hdac_i915.c
+++ b/sound/hda/hdac_i915.c
@@ -143,10 +143,12 @@ int snd_hdac_i915_init(struct hdac_bus *bus)
if (!acomp)
return -ENODEV;
if (!acomp->ops) {
- request_module("i915");
- /* 60s timeout */
- wait_for_completion_timeout(&bind_complete,
- msecs_to_jiffies(60 * 1000));
+ if (!IS_ENABLED(CONFIG_MODULES) ||
+ !request_module("i915")) {
+ /* 60s timeout */
+ wait_for_completion_timeout(&bind_complete,
+ msecs_to_jiffies(60 * 1000));
+ }
}
if (!acomp->ops) {
dev_info(bus->dev, "couldn't bind with audio component\n");
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 3cbd211..b70fbfa 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -1096,6 +1096,7 @@ static int patch_conexant_auto(struct hda_codec *codec)
*/
static const struct hda_device_id snd_hda_id_conexant[] = {
+ HDA_CODEC_ENTRY(0x14f11f86, "CX8070", patch_conexant_auto),
HDA_CODEC_ENTRY(0x14f12008, "CX8200", patch_conexant_auto),
HDA_CODEC_ENTRY(0x14f15045, "CX20549 (Venice)", patch_conexant_auto),
HDA_CODEC_ENTRY(0x14f15047, "CX20551 (Waikiki)", patch_conexant_auto),
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 6453370..dc19896 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -3236,6 +3236,7 @@ static void alc256_init(struct hda_codec *codec)
alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */
alc_update_coefex_idx(codec, 0x53, 0x02, 0x8000, 1 << 15); /* Clear bit */
alc_update_coefex_idx(codec, 0x53, 0x02, 0x8000, 0 << 15);
+ alc_update_coef_idx(codec, 0x36, 1 << 13, 1 << 5); /* Switch pcbeep path to Line in path*/
}
static void alc256_shutup(struct hda_codec *codec)
@@ -7517,9 +7518,12 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
{0x12, 0x90a60130},
{0x17, 0x90170110},
{0x21, 0x03211020}),
- SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
+ SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
{0x14, 0x90170110},
{0x21, 0x04211020}),
+ SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
+ {0x14, 0x90170110},
+ {0x21, 0x04211030}),
SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
ALC295_STANDARD_PINS,
{0x17, 0x21014020},
@@ -7686,7 +7690,6 @@ static int patch_alc269(struct hda_codec *codec)
spec->shutup = alc256_shutup;
spec->init_hook = alc256_init;
spec->gen.mixer_nid = 0; /* ALC256 does not have any loopback mixer path */
- alc_update_coef_idx(codec, 0x36, 1 << 13, 1 << 5); /* Switch pcbeep path to Line in path*/
break;
case 0x10ec0257:
spec->codec_variant = ALC269_TYPE_ALC257;
@@ -8654,6 +8657,11 @@ static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = {
{0x18, 0x01a19030},
{0x1a, 0x01813040},
{0x21, 0x01014020}),
+ SND_HDA_PIN_QUIRK(0x10ec0867, 0x1028, "Dell", ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
+ {0x16, 0x01813030},
+ {0x17, 0x02211010},
+ {0x18, 0x01a19040},
+ {0x21, 0x01014020}),
SND_HDA_PIN_QUIRK(0x10ec0662, 0x1028, "Dell", ALC662_FIXUP_DELL_MIC_NO_PRESENCE,
{0x14, 0x01014010},
{0x18, 0x01a19020},
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index 6348724..0981966 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -1854,6 +1854,12 @@ static void hdmi_codec_remove(struct snd_soc_component *component)
{
struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component);
struct hdac_device *hdev = hdmi->hdev;
+ int ret;
+
+ ret = snd_hdac_acomp_register_notifier(hdev->bus, NULL);
+ if (ret < 0)
+ dev_err(&hdev->dev, "notifier unregister failed: err: %d\n",
+ ret);
pm_runtime_disable(&hdev->dev);
}
diff --git a/sound/soc/meson/axg-tdm.h b/sound/soc/meson/axg-tdm.h
index e578b6f4..5774ce0 100644
--- a/sound/soc/meson/axg-tdm.h
+++ b/sound/soc/meson/axg-tdm.h
@@ -40,7 +40,7 @@ struct axg_tdm_iface {
static inline bool axg_tdm_lrclk_invert(unsigned int fmt)
{
- return (fmt & SND_SOC_DAIFMT_I2S) ^
+ return ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S) ^
!!(fmt & (SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_NB_IF));
}
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index cb0b106..91cc574 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -2150,23 +2150,25 @@ void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
{
struct dentry *d;
- if (!parent)
+ if (!parent || IS_ERR(parent))
return;
dapm->debugfs_dapm = debugfs_create_dir("dapm", parent);
- if (!dapm->debugfs_dapm) {
+ if (IS_ERR(dapm->debugfs_dapm)) {
dev_warn(dapm->dev,
- "ASoC: Failed to create DAPM debugfs directory\n");
+ "ASoC: Failed to create DAPM debugfs directory %ld\n",
+ PTR_ERR(dapm->debugfs_dapm));
return;
}
d = debugfs_create_file("bias_level", 0444,
dapm->debugfs_dapm, dapm,
&dapm_bias_fops);
- if (!d)
+ if (IS_ERR(d))
dev_warn(dapm->dev,
- "ASoC: Failed to create bias level debugfs file\n");
+ "ASoC: Failed to create bias level debugfs file: %ld\n",
+ PTR_ERR(d));
}
static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
@@ -2180,10 +2182,10 @@ static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
d = debugfs_create_file(w->name, 0444,
dapm->debugfs_dapm, w,
&dapm_widget_power_fops);
- if (!d)
+ if (IS_ERR(d))
dev_warn(w->dapm->dev,
- "ASoC: Failed to create %s debugfs file\n",
- w->name);
+ "ASoC: Failed to create %s debugfs file: %ld\n",
+ w->name, PTR_ERR(d));
}
static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
diff --git a/sound/usb/line6/podhd.c b/sound/usb/line6/podhd.c
index 5f3c872..da627b0 100644
--- a/sound/usb/line6/podhd.c
+++ b/sound/usb/line6/podhd.c
@@ -417,7 +417,7 @@ static const struct line6_properties podhd_properties_table[] = {
.name = "POD HD500",
.capabilities = LINE6_CAP_PCM
| LINE6_CAP_HWMON,
- .altsetting = 1,
+ .altsetting = 0,
.ep_ctrl_r = 0x81,
.ep_ctrl_w = 0x01,
.ep_audio_r = 0x86,
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 1056628..e63a7d3 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -2324,7 +2324,7 @@ static struct procunit_info extunits[] = {
*/
static int build_audio_procunit(struct mixer_build *state, int unitid,
void *raw_desc, struct procunit_info *list,
- char *name)
+ bool extension_unit)
{
struct uac_processing_unit_descriptor *desc = raw_desc;
int num_ins;
@@ -2341,6 +2341,8 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
static struct procunit_info default_info = {
0, NULL, default_value_info
};
+ const char *name = extension_unit ?
+ "Extension Unit" : "Processing Unit";
if (desc->bLength < 13) {
usb_audio_err(state->chip, "invalid %s descriptor (id %d)\n", name, unitid);
@@ -2454,7 +2456,10 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
} else if (info->name) {
strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name));
} else {
- nameid = uac_processing_unit_iProcessing(desc, state->mixer->protocol);
+ if (extension_unit)
+ nameid = uac_extension_unit_iExtension(desc, state->mixer->protocol);
+ else
+ nameid = uac_processing_unit_iProcessing(desc, state->mixer->protocol);
len = 0;
if (nameid)
len = snd_usb_copy_string_desc(state->chip,
@@ -2487,10 +2492,10 @@ static int parse_audio_processing_unit(struct mixer_build *state, int unitid,
case UAC_VERSION_2:
default:
return build_audio_procunit(state, unitid, raw_desc,
- procunits, "Processing Unit");
+ procunits, false);
case UAC_VERSION_3:
return build_audio_procunit(state, unitid, raw_desc,
- uac3_procunits, "Processing Unit");
+ uac3_procunits, false);
}
}
@@ -2501,8 +2506,7 @@ static int parse_audio_extension_unit(struct mixer_build *state, int unitid,
* Note that we parse extension units with processing unit descriptors.
* That's ok as the layout is the same.
*/
- return build_audio_procunit(state, unitid, raw_desc,
- extunits, "Extension Unit");
+ return build_audio_procunit(state, unitid, raw_desc, extunits, true);
}
/*
diff --git a/tools/bpf/bpftool/jit_disasm.c b/tools/bpf/bpftool/jit_disasm.c
index 8743932..73d7252 100644
--- a/tools/bpf/bpftool/jit_disasm.c
+++ b/tools/bpf/bpftool/jit_disasm.c
@@ -10,6 +10,8 @@
* Licensed under the GNU General Public License, version 2.0 (GPLv2)
*/
+#define _GNU_SOURCE
+#include <stdio.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
@@ -51,11 +53,13 @@ static int fprintf_json(void *out, const char *fmt, ...)
char *s;
va_start(ap, fmt);
+ if (vasprintf(&s, fmt, ap) < 0)
+ return -1;
+ va_end(ap);
+
if (!oper_count) {
int i;
- s = va_arg(ap, char *);
-
/* Strip trailing spaces */
i = strlen(s) - 1;
while (s[i] == ' ')
@@ -68,11 +72,10 @@ static int fprintf_json(void *out, const char *fmt, ...)
} else if (!strcmp(fmt, ",")) {
/* Skip */
} else {
- s = va_arg(ap, char *);
jsonw_string(json_wtr, s);
oper_count++;
}
- va_end(ap);
+ free(s);
return 0;
}
diff --git a/tools/iio/iio_utils.c b/tools/iio/iio_utils.c
index 7a6d61c..55272fe 100644
--- a/tools/iio/iio_utils.c
+++ b/tools/iio/iio_utils.c
@@ -159,9 +159,9 @@ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used,
*be = (endianchar == 'b');
*bytes = padint / 8;
if (*bits_used == 64)
- *mask = ~0;
+ *mask = ~(0ULL);
else
- *mask = (1ULL << *bits_used) - 1;
+ *mask = (1ULL << *bits_used) - 1ULL;
*is_signed = (signchar == 's');
if (fclose(sysfsfp)) {
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 66917a4..bf4cd92 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -2484,6 +2484,7 @@ struct bpf_prog_info {
char name[BPF_OBJ_NAME_LEN];
__u32 ifindex;
__u32 gpl_compatible:1;
+ __u32 :31; /* alignment pad */
__u64 netns_dev;
__u64 netns_ino;
__u32 nr_jited_ksyms;
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index bdb9493..a350f97 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -2293,10 +2293,7 @@ int bpf_prog_load(const char *file, enum bpf_prog_type type,
int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
struct bpf_object **pobj, int *prog_fd)
{
- struct bpf_object_open_attr open_attr = {
- .file = attr->file,
- .prog_type = attr->prog_type,
- };
+ struct bpf_object_open_attr open_attr = {};
struct bpf_program *prog, *first_prog = NULL;
enum bpf_attach_type expected_attach_type;
enum bpf_prog_type prog_type;
@@ -2309,6 +2306,9 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
if (!attr->file)
return -EINVAL;
+ open_attr.file = attr->file;
+ open_attr.prog_type = attr->prog_type;
+
obj = bpf_object__open_xattr(&open_attr);
if (IS_ERR_OR_NULL(obj))
return -ENOENT;
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index abed594..b8f3cca 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -305,7 +305,7 @@ static int read_symbols(struct elf *elf)
if (sym->type != STT_FUNC)
continue;
sym->pfunc = sym->cfunc = sym;
- coldstr = strstr(sym->name, ".cold.");
+ coldstr = strstr(sym->name, ".cold");
if (!coldstr)
continue;
diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c
index 2f595cd..16af6c3 100644
--- a/tools/perf/arch/arm/util/cs-etm.c
+++ b/tools/perf/arch/arm/util/cs-etm.c
@@ -32,6 +32,8 @@ struct cs_etm_recording {
struct auxtrace_record itr;
struct perf_pmu *cs_etm_pmu;
struct perf_evlist *evlist;
+ int wrapped_cnt;
+ bool *wrapped;
bool snapshot_mode;
size_t snapshot_size;
};
@@ -495,16 +497,131 @@ static int cs_etm_info_fill(struct auxtrace_record *itr,
return 0;
}
-static int cs_etm_find_snapshot(struct auxtrace_record *itr __maybe_unused,
+static int cs_etm_alloc_wrapped_array(struct cs_etm_recording *ptr, int idx)
+{
+ bool *wrapped;
+ int cnt = ptr->wrapped_cnt;
+
+ /* Make @ptr->wrapped as big as @idx */
+ while (cnt <= idx)
+ cnt++;
+
+ /*
+ * Free'ed in cs_etm_recording_free(). Using realloc() to avoid
+ * cross compilation problems where the host's system supports
+ * reallocarray() but not the target.
+ */
+ wrapped = realloc(ptr->wrapped, cnt * sizeof(bool));
+ if (!wrapped)
+ return -ENOMEM;
+
+ wrapped[cnt - 1] = false;
+ ptr->wrapped_cnt = cnt;
+ ptr->wrapped = wrapped;
+
+ return 0;
+}
+
+static bool cs_etm_buffer_has_wrapped(unsigned char *buffer,
+ size_t buffer_size, u64 head)
+{
+ u64 i, watermark;
+ u64 *buf = (u64 *)buffer;
+ size_t buf_size = buffer_size;
+
+ /*
+ * We want to look the very last 512 byte (chosen arbitrarily) in
+ * the ring buffer.
+ */
+ watermark = buf_size - 512;
+
+ /*
+ * @head is continuously increasing - if its value is equal or greater
+ * than the size of the ring buffer, it has wrapped around.
+ */
+ if (head >= buffer_size)
+ return true;
+
+ /*
+ * The value of @head is somewhere within the size of the ring buffer.
+ * This can be that there hasn't been enough data to fill the ring
+ * buffer yet or the trace time was so long that @head has numerically
+ * wrapped around. To find we need to check if we have data at the very
+ * end of the ring buffer. We can reliably do this because mmap'ed
+ * pages are zeroed out and there is a fresh mapping with every new
+ * session.
+ */
+
+ /* @head is less than 512 byte from the end of the ring buffer */
+ if (head > watermark)
+ watermark = head;
+
+ /*
+ * Speed things up by using 64 bit transactions (see "u64 *buf" above)
+ */
+ watermark >>= 3;
+ buf_size >>= 3;
+
+ /*
+ * If we find trace data at the end of the ring buffer, @head has
+ * been there and has numerically wrapped around at least once.
+ */
+ for (i = watermark; i < buf_size; i++)
+ if (buf[i])
+ return true;
+
+ return false;
+}
+
+static int cs_etm_find_snapshot(struct auxtrace_record *itr,
int idx, struct auxtrace_mmap *mm,
- unsigned char *data __maybe_unused,
+ unsigned char *data,
u64 *head, u64 *old)
{
+ int err;
+ bool wrapped;
+ struct cs_etm_recording *ptr =
+ container_of(itr, struct cs_etm_recording, itr);
+
+ /*
+ * Allocate memory to keep track of wrapping if this is the first
+ * time we deal with this *mm.
+ */
+ if (idx >= ptr->wrapped_cnt) {
+ err = cs_etm_alloc_wrapped_array(ptr, idx);
+ if (err)
+ return err;
+ }
+
+ /*
+ * Check to see if *head has wrapped around. If it hasn't only the
+ * amount of data between *head and *old is snapshot'ed to avoid
+ * bloating the perf.data file with zeros. But as soon as *head has
+ * wrapped around the entire size of the AUX ring buffer it taken.
+ */
+ wrapped = ptr->wrapped[idx];
+ if (!wrapped && cs_etm_buffer_has_wrapped(data, mm->len, *head)) {
+ wrapped = true;
+ ptr->wrapped[idx] = true;
+ }
+
pr_debug3("%s: mmap index %d old head %zu new head %zu size %zu\n",
__func__, idx, (size_t)*old, (size_t)*head, mm->len);
- *old = *head;
- *head += mm->len;
+ /* No wrap has occurred, we can just use *head and *old. */
+ if (!wrapped)
+ return 0;
+
+ /*
+ * *head has wrapped around - adjust *head and *old to pickup the
+ * entire content of the AUX buffer.
+ */
+ if (*head >= mm->len) {
+ *old = *head - mm->len;
+ } else {
+ *head += mm->len;
+ *old = *head - mm->len;
+ }
return 0;
}
@@ -545,6 +662,8 @@ static void cs_etm_recording_free(struct auxtrace_record *itr)
{
struct cs_etm_recording *ptr =
container_of(itr, struct cs_etm_recording, itr);
+
+ zfree(&ptr->wrapped);
free(ptr);
}
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 4072015..7899625 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -2497,8 +2497,8 @@ static int add_default_attributes(void)
fprintf(stderr,
"Cannot set up top down events %s: %d\n",
str, err);
- free(str);
parse_events_print_error(&errinfo, str);
+ free(str);
return -1;
}
} else {
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 33eefc3..d073325 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -99,7 +99,7 @@ static void perf_top__resize(struct perf_top *top)
static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
{
- struct perf_evsel *evsel = hists_to_evsel(he->hists);
+ struct perf_evsel *evsel;
struct symbol *sym;
struct annotation *notes;
struct map *map;
@@ -108,6 +108,8 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
if (!he || !he->ms.sym)
return -1;
+ evsel = hists_to_evsel(he->hists);
+
sym = he->ms.sym;
map = he->ms.map;
@@ -224,7 +226,7 @@ static void perf_top__record_precise_ip(struct perf_top *top,
static void perf_top__show_details(struct perf_top *top)
{
struct hist_entry *he = top->sym_filter_entry;
- struct perf_evsel *evsel = hists_to_evsel(he->hists);
+ struct perf_evsel *evsel;
struct annotation *notes;
struct symbol *symbol;
int more;
@@ -232,6 +234,8 @@ static void perf_top__show_details(struct perf_top *top)
if (!he)
return;
+ evsel = hists_to_evsel(he->hists);
+
symbol = he->ms.sym;
notes = symbol__annotation(symbol);
diff --git a/tools/perf/builtin-version.c b/tools/perf/builtin-version.c
index 50df168..b02c961 100644
--- a/tools/perf/builtin-version.c
+++ b/tools/perf/builtin-version.c
@@ -19,6 +19,7 @@ static struct version version;
static struct option version_options[] = {
OPT_BOOLEAN(0, "build-options", &version.build_options,
"display the build options"),
+ OPT_END(),
};
static const char * const version_usage[] = {
diff --git a/tools/perf/jvmti/libjvmti.c b/tools/perf/jvmti/libjvmti.c
index 6add3e9..3361d98 100644
--- a/tools/perf/jvmti/libjvmti.c
+++ b/tools/perf/jvmti/libjvmti.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/compiler.h>
+#include <linux/string.h>
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
@@ -150,8 +151,7 @@ copy_class_filename(const char * class_sign, const char * file_name, char * resu
result[i] = '\0';
} else {
/* fallback case */
- size_t file_name_len = strlen(file_name);
- strncpy(result, file_name, file_name_len < max_length ? file_name_len : max_length);
+ strlcpy(result, file_name, max_length);
}
}
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 21bf7f5..19d435a 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -26,7 +26,7 @@ static inline unsigned long long rdclock(void)
}
#ifndef MAX_NR_CPUS
-#define MAX_NR_CPUS 1024
+#define MAX_NR_CPUS 2048
#endif
extern const char *input_name;
diff --git a/tools/perf/tests/mmap-thread-lookup.c b/tools/perf/tests/mmap-thread-lookup.c
index b1af249..7a9b123 100644
--- a/tools/perf/tests/mmap-thread-lookup.c
+++ b/tools/perf/tests/mmap-thread-lookup.c
@@ -52,7 +52,7 @@ static void *thread_fn(void *arg)
{
struct thread_data *td = arg;
ssize_t ret;
- int go;
+ int go = 0;
if (thread_init(td))
return NULL;
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 3b97ac0..532c95e 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -18,6 +18,32 @@
#define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \
PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD)
+#if defined(__s390x__)
+/* Return true if kvm module is available and loaded. Test this
+ * and retun success when trace point kvm_s390_create_vm
+ * exists. Otherwise this test always fails.
+ */
+static bool kvm_s390_create_vm_valid(void)
+{
+ char *eventfile;
+ bool rc = false;
+
+ eventfile = get_events_file("kvm-s390");
+
+ if (eventfile) {
+ DIR *mydir = opendir(eventfile);
+
+ if (mydir) {
+ rc = true;
+ closedir(mydir);
+ }
+ put_events_file(eventfile);
+ }
+
+ return rc;
+}
+#endif
+
static int test__checkevent_tracepoint(struct perf_evlist *evlist)
{
struct perf_evsel *evsel = perf_evlist__first(evlist);
@@ -1622,6 +1648,7 @@ static struct evlist_test test__events[] = {
{
.name = "kvm-s390:kvm_s390_create_vm",
.check = test__checkevent_tracepoint,
+ .valid = kvm_s390_create_vm_valid,
.id = 100,
},
#endif
diff --git a/tools/perf/tests/shell/record+probe_libc_inet_pton.sh b/tools/perf/tests/shell/record+probe_libc_inet_pton.sh
index cab7b0a..f5837f28 100755
--- a/tools/perf/tests/shell/record+probe_libc_inet_pton.sh
+++ b/tools/perf/tests/shell/record+probe_libc_inet_pton.sh
@@ -43,7 +43,7 @@
eventattr='max-stack=4'
echo "gaih_inet.*\+0x[[:xdigit:]]+[[:space:]]\($libc\)$" >> $expected
echo "getaddrinfo\+0x[[:xdigit:]]+[[:space:]]\($libc\)$" >> $expected
- echo ".*\+0x[[:xdigit:]]+[[:space:]]\(.*/bin/ping.*\)$" >> $expected
+ echo ".*(\+0x[[:xdigit:]]+|\[unknown\])[[:space:]]\(.*/bin/ping.*\)$" >> $expected
;;
*)
eventattr='max-stack=3'
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index 1d00e5e..a3c2552 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -96,11 +96,12 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
struct annotation *notes = browser__annotation(browser);
struct annotation_line *al = list_entry(entry, struct annotation_line, node);
+ const bool is_current_entry = ui_browser__is_current_entry(browser, row);
struct annotation_write_ops ops = {
.first_line = row == 0,
- .current_entry = ui_browser__is_current_entry(browser, row),
+ .current_entry = is_current_entry,
.change_color = (!notes->options->hide_src_code &&
- (!ops.current_entry ||
+ (!is_current_entry ||
(browser->use_navkeypressed &&
!browser->navkeypressed))),
.width = browser->width,
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index a96f62c..692d2fa 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -633,7 +633,11 @@ int hist_browser__run(struct hist_browser *browser, const char *help,
switch (key) {
case K_TIMER: {
u64 nr_entries;
- hbt->timer(hbt->arg);
+
+ WARN_ON_ONCE(!hbt);
+
+ if (hbt)
+ hbt->timer(hbt->arg);
if (hist_browser__has_filter(browser) ||
symbol_conf.report_hierarchy)
@@ -2707,7 +2711,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
{
struct hists *hists = evsel__hists(evsel);
struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env, annotation_opts);
- struct branch_info *bi;
+ struct branch_info *bi = NULL;
#define MAX_OPTIONS 16
char *options[MAX_OPTIONS];
struct popup_action actions[MAX_OPTIONS];
@@ -2973,7 +2977,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
goto skip_annotation;
if (sort__mode == SORT_MODE__BRANCH) {
- bi = browser->he_selection->branch_info;
+
+ if (browser->he_selection)
+ bi = browser->he_selection->branch_info;
if (bi == NULL)
goto skip_annotation;
@@ -3144,7 +3150,8 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
switch (key) {
case K_TIMER:
- hbt->timer(hbt->arg);
+ if (hbt)
+ hbt->timer(hbt->arg);
if (!menu->lost_events_warned &&
menu->lost_events &&
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index dfee110..daea1fd 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -911,9 +911,8 @@ static int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
if (sym == NULL)
return 0;
src = symbol__hists(sym, evsel->evlist->nr_entries);
- if (src == NULL)
- return -ENOMEM;
- return __symbol__inc_addr_samples(sym, map, src, evsel->idx, addr, sample);
+ return (src) ? __symbol__inc_addr_samples(sym, map, src, evsel->idx,
+ addr, sample) : 0;
}
static int symbol__account_cycles(u64 addr, u64 start,
@@ -1080,16 +1079,14 @@ static int disasm_line__parse(char *line, const char **namep, char **rawp)
*namep = strdup(name);
if (*namep == NULL)
- goto out_free_name;
+ goto out;
(*rawp)[0] = tmp;
*rawp = ltrim(*rawp);
return 0;
-out_free_name:
- free((void *)namep);
- *namep = NULL;
+out:
return -1;
}
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index b65ad5a..4fad922 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -590,6 +590,9 @@ const char *perf_evsel__name(struct perf_evsel *evsel)
{
char bf[128];
+ if (!evsel)
+ goto out_unknown;
+
if (evsel->name)
return evsel->name;
@@ -626,7 +629,10 @@ const char *perf_evsel__name(struct perf_evsel *evsel)
evsel->name = strdup(bf);
- return evsel->name ?: "unknown";
+ if (evsel->name)
+ return evsel->name;
+out_unknown:
+ return "unknown";
}
const char *perf_evsel__group_name(struct perf_evsel *evsel)
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index b9a8259..7f2e3b1 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1173,7 +1173,7 @@ static int build_caches(struct cpu_cache_level caches[], u32 size, u32 *cntp)
return 0;
}
-#define MAX_CACHES 2000
+#define MAX_CACHES (MAX_NR_CPUS * 4)
static int write_cache(struct feat_fd *ff,
struct perf_evlist *evlist __maybe_unused)
diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c
index a28f9b5..8b3dafe 100644
--- a/tools/perf/util/metricgroup.c
+++ b/tools/perf/util/metricgroup.c
@@ -94,26 +94,49 @@ struct egroup {
const char *metric_expr;
};
-static struct perf_evsel *find_evsel(struct perf_evlist *perf_evlist,
- const char **ids,
- int idnum,
- struct perf_evsel **metric_events)
+static bool record_evsel(int *ind, struct perf_evsel **start,
+ int idnum,
+ struct perf_evsel **metric_events,
+ struct perf_evsel *ev)
+{
+ metric_events[*ind] = ev;
+ if (*ind == 0)
+ *start = ev;
+ if (++*ind == idnum) {
+ metric_events[*ind] = NULL;
+ return true;
+ }
+ return false;
+}
+
+static struct perf_evsel *find_evsel_group(struct perf_evlist *perf_evlist,
+ const char **ids,
+ int idnum,
+ struct perf_evsel **metric_events)
{
struct perf_evsel *ev, *start = NULL;
int ind = 0;
evlist__for_each_entry (perf_evlist, ev) {
+ if (ev->collect_stat)
+ continue;
if (!strcmp(ev->name, ids[ind])) {
- metric_events[ind] = ev;
- if (ind == 0)
- start = ev;
- if (++ind == idnum) {
- metric_events[ind] = NULL;
+ if (record_evsel(&ind, &start, idnum,
+ metric_events, ev))
return start;
- }
} else {
+ /*
+ * We saw some other event that is not
+ * in our list of events. Discard
+ * the whole match and start again.
+ */
ind = 0;
start = NULL;
+ if (!strcmp(ev->name, ids[ind])) {
+ if (record_evsel(&ind, &start, idnum,
+ metric_events, ev))
+ return start;
+ }
}
}
/*
@@ -143,8 +166,8 @@ static int metricgroup__setup_events(struct list_head *groups,
ret = -ENOMEM;
break;
}
- evsel = find_evsel(perf_evlist, eg->ids, eg->idnum,
- metric_events);
+ evsel = find_evsel_group(perf_evlist, eg->ids, eg->idnum,
+ metric_events);
if (!evsel) {
pr_debug("Cannot resolve %s: %s\n",
eg->metric_name, eg->metric_expr);
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 36cfc64..c1acf04 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -750,9 +750,7 @@ static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
{
int i;
struct pmu_events_map *map;
- struct pmu_event *pe;
const char *name = pmu->name;
- const char *pname;
map = perf_pmu__find_map(pmu);
if (!map)
@@ -763,28 +761,26 @@ static void pmu_add_cpu_aliases(struct list_head *head, struct perf_pmu *pmu)
*/
i = 0;
while (1) {
+ const char *cpu_name = is_arm_pmu_core(name) ? name : "cpu";
+ struct pmu_event *pe = &map->table[i++];
+ const char *pname = pe->pmu ? pe->pmu : cpu_name;
- pe = &map->table[i++];
if (!pe->name) {
if (pe->metric_group || pe->metric_name)
continue;
break;
}
- if (!is_arm_pmu_core(name)) {
- pname = pe->pmu ? pe->pmu : "cpu";
+ /*
+ * uncore alias may be from different PMU
+ * with common prefix
+ */
+ if (pmu_is_uncore(name) &&
+ !strncmp(pname, name, strlen(pname)))
+ goto new_alias;
- /*
- * uncore alias may be from different PMU
- * with common prefix
- */
- if (pmu_is_uncore(name) &&
- !strncmp(pname, name, strlen(pname)))
- goto new_alias;
-
- if (strcmp(pname, name))
- continue;
- }
+ if (strcmp(pname, name))
+ continue;
new_alias:
/* need type casts to override 'const' */
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 1108609..f016d1b 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1141,6 +1141,9 @@ static void dump_read(struct perf_evsel *evsel, union perf_event *event)
evsel ? perf_evsel__name(evsel) : "FAIL",
event->read.value);
+ if (!evsel)
+ return;
+
read_format = evsel->attr.read_format;
if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c
index 99990f5..bbb0e04 100644
--- a/tools/perf/util/stat-shadow.c
+++ b/tools/perf/util/stat-shadow.c
@@ -303,7 +303,7 @@ static struct perf_evsel *perf_stat__find_event(struct perf_evlist *evsel_list,
struct perf_evsel *c2;
evlist__for_each_entry (evsel_list, c2) {
- if (!strcasecmp(c2->name, name))
+ if (!strcasecmp(c2->name, name) && !c2->collect_stat)
return c2;
}
return NULL;
@@ -342,7 +342,8 @@ void perf_stat__collect_metric_expr(struct perf_evlist *evsel_list)
if (leader) {
/* Search in group */
for_each_group_member (oc, leader) {
- if (!strcasecmp(oc->name, metric_names[i])) {
+ if (!strcasecmp(oc->name, metric_names[i]) &&
+ !oc->collect_stat) {
found = true;
break;
}
diff --git a/tools/power/cpupower/utils/cpufreq-set.c b/tools/power/cpupower/utils/cpufreq-set.c
index 1eef0ae..08a4055 100644
--- a/tools/power/cpupower/utils/cpufreq-set.c
+++ b/tools/power/cpupower/utils/cpufreq-set.c
@@ -306,6 +306,8 @@ int cmd_freq_set(int argc, char **argv)
bitmask_setbit(cpus_chosen, cpus->cpu);
cpus = cpus->next;
}
+ /* Set the last cpu in related cpus list */
+ bitmask_setbit(cpus_chosen, cpus->cpu);
cpufreq_put_related_cpus(cpus);
}
}
diff --git a/tools/testing/selftests/bpf/test_lwt_seg6local.c b/tools/testing/selftests/bpf/test_lwt_seg6local.c
index 0575751..e2f6ed0 100644
--- a/tools/testing/selftests/bpf/test_lwt_seg6local.c
+++ b/tools/testing/selftests/bpf/test_lwt_seg6local.c
@@ -61,7 +61,7 @@ struct sr6_tlv_t {
unsigned char value[0];
} BPF_PACKET_HEADER;
-__attribute__((always_inline)) struct ip6_srh_t *get_srh(struct __sk_buff *skb)
+static __always_inline struct ip6_srh_t *get_srh(struct __sk_buff *skb)
{
void *cursor, *data_end;
struct ip6_srh_t *srh;
@@ -95,7 +95,7 @@ __attribute__((always_inline)) struct ip6_srh_t *get_srh(struct __sk_buff *skb)
return srh;
}
-__attribute__((always_inline))
+static __always_inline
int update_tlv_pad(struct __sk_buff *skb, uint32_t new_pad,
uint32_t old_pad, uint32_t pad_off)
{
@@ -125,7 +125,7 @@ int update_tlv_pad(struct __sk_buff *skb, uint32_t new_pad,
return 0;
}
-__attribute__((always_inline))
+static __always_inline
int is_valid_tlv_boundary(struct __sk_buff *skb, struct ip6_srh_t *srh,
uint32_t *tlv_off, uint32_t *pad_size,
uint32_t *pad_off)
@@ -184,7 +184,7 @@ int is_valid_tlv_boundary(struct __sk_buff *skb, struct ip6_srh_t *srh,
return 0;
}
-__attribute__((always_inline))
+static __always_inline
int add_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh, uint32_t tlv_off,
struct sr6_tlv_t *itlv, uint8_t tlv_size)
{
@@ -228,7 +228,7 @@ int add_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh, uint32_t tlv_off,
return update_tlv_pad(skb, new_pad, pad_size, pad_off);
}
-__attribute__((always_inline))
+static __always_inline
int delete_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh,
uint32_t tlv_off)
{
@@ -266,7 +266,7 @@ int delete_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh,
return update_tlv_pad(skb, new_pad, pad_size, pad_off);
}
-__attribute__((always_inline))
+static __always_inline
int has_egr_tlv(struct __sk_buff *skb, struct ip6_srh_t *srh)
{
int tlv_offset = sizeof(struct ip6_t) + sizeof(struct ip6_srh_t) +
diff --git a/tools/testing/selftests/cgroup/cgroup_util.c b/tools/testing/selftests/cgroup/cgroup_util.c
index 14c9fe2..075cb0c73 100644
--- a/tools/testing/selftests/cgroup/cgroup_util.c
+++ b/tools/testing/selftests/cgroup/cgroup_util.c
@@ -181,8 +181,7 @@ int cg_find_unified_root(char *root, size_t len)
strtok(NULL, delim);
strtok(NULL, delim);
- if (strcmp(fs, "cgroup") == 0 &&
- strcmp(type, "cgroup2") == 0) {
+ if (strcmp(type, "cgroup2") == 0) {
strncpy(root, mount, len);
return 0;
}
diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 621bb00..0dbe332 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -1750,6 +1750,7 @@ static void vgic_its_destroy(struct kvm_device *kvm_dev)
mutex_unlock(&its->its_lock);
kfree(its);
+ kfree(kvm_dev);/* alloc by kvm_ioctl_create_device, free by .destroy */
}
int vgic_its_has_attr_regs(struct kvm_device *dev,