diff --git a/AndroidKernel.mk b/AndroidKernel.mk index 35d3573210c615e266e3d21e2186c947a2efa3f5..900c01e580057e27fabb5e2116ba2fec6013ab76 100644 --- a/AndroidKernel.mk +++ b/AndroidKernel.mk @@ -48,7 +48,7 @@ TARGET_KERNEL_CROSS_COMPILE_PREFIX := $(strip $(TARGET_KERNEL_CROSS_COMPILE_PREF ifeq ($(TARGET_KERNEL_CROSS_COMPILE_PREFIX),) KERNEL_CROSS_COMPILE := arm-eabi- else -KERNEL_CROSS_COMPILE := $(TARGET_KERNEL_CROSS_COMPILE_PREFIX) +KERNEL_CROSS_COMPILE := $(shell pwd)/$(TARGET_TOOLS_PREFIX) endif ifeq ($(KERNEL_LLVM_SUPPORT), true) @@ -56,11 +56,11 @@ ifeq ($(KERNEL_LLVM_SUPPORT), true) ifeq ($(shell echo $(SDCLANG_PATH) | head -c 1),/) KERNEL_LLVM_BIN := $(SDCLANG_PATH)/clang else - KERNEL_LLVM_BIN := $(ANDROID_BUILD_TOP)/$(SDCLANG_PATH)/clang + KERNEL_LLVM_BIN := $(shell pwd)/$(SDCLANG_PATH)/clang endif $(warning "Using sdllvm" $(KERNEL_LLVM_BIN)) else - KERNEL_LLVM_BIN := $(ANDROID_BUILD_TOP)/$(CLANG) #Using aosp-llvm compiler + KERNEL_LLVM_BIN := $(shell pwd)/$(CLANG) #Using aosp-llvm compiler $(warning "Using aosp-llvm" $(KERNEL_LLVM_BIN)) endif endif diff --git a/Documentation/ABI/testing/sysfs-block-zram b/Documentation/ABI/testing/sysfs-block-zram index c1513c756af125ce5adb76ee8e4522e25572a099..e757ac8142d576f241362b2912d6296c603aba39 100644 --- a/Documentation/ABI/testing/sysfs-block-zram +++ b/Documentation/ABI/testing/sysfs-block-zram @@ -98,3 +98,13 @@ Description: The backing_dev file is read-write and set up backing device for zram to write incompressible pages. For using, user should enable CONFIG_ZRAM_WRITEBACK. + +What: /sys/block/zram/use_dedup +Date: March 2017 +Contact: Joonsoo Kim +Description: + The use_dedup file is read-write and specifies deduplication + feature is used or not. If enabled, duplicated data is + managed by reference count and will not be stored in memory + twice. Benefit of this feature largely depends on the workload + so keep attention when use. diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu index 8355e79350b79cf8789719d20e48f34497fee93b..6cae60929cb6f4446e73b5104aaf356a4c4bf3a0 100644 --- a/Documentation/ABI/testing/sysfs-devices-system-cpu +++ b/Documentation/ABI/testing/sysfs-devices-system-cpu @@ -379,6 +379,7 @@ What: /sys/devices/system/cpu/vulnerabilities /sys/devices/system/cpu/vulnerabilities/spectre_v1 /sys/devices/system/cpu/vulnerabilities/spectre_v2 /sys/devices/system/cpu/vulnerabilities/spec_store_bypass + /sys/devices/system/cpu/vulnerabilities/l1tf Date: January 2018 Contact: Linux kernel mailing list Description: Information about CPU vulnerabilities @@ -390,3 +391,26 @@ Description: Information about CPU vulnerabilities "Not affected" CPU is not affected by the vulnerability "Vulnerable" CPU is affected and no mitigation in effect "Mitigation: $M" CPU is affected and mitigation $M is in effect + + Details about the l1tf file can be found in + Documentation/admin-guide/l1tf.rst + +What: /sys/devices/system/cpu/smt + /sys/devices/system/cpu/smt/active + /sys/devices/system/cpu/smt/control +Date: June 2018 +Contact: Linux kernel mailing list +Description: Control Symetric Multi Threading (SMT) + + active: Tells whether SMT is active (enabled and siblings online) + + control: Read/write interface to control SMT. Possible + values: + + "on" SMT is enabled + "off" SMT is disabled + "forceoff" SMT is force disabled. Cannot be changed. + "notsupported" SMT is not supported by the CPU + + If control status is "forceoff" or "notsupported" writes + are rejected. diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs index 372b88f4e706250123ef30b8a851b8c8bd02b8d2..41b8cb3b4525669e611f1981485a863df6649369 100644 --- a/Documentation/ABI/testing/sysfs-fs-f2fs +++ b/Documentation/ABI/testing/sysfs-fs-f2fs @@ -51,6 +51,14 @@ Description: Controls the dirty page count condition for the in-place-update policies. +What: /sys/fs/f2fs//min_seq_blocks +Date: August 2018 +Contact: "Jaegeuk Kim" +Description: + Controls the dirty page count condition for batched sequential + writes in ->writepages. + + What: /sys/fs/f2fs//min_hot_blocks Date: March 2017 Contact: "Jaegeuk Kim" diff --git a/Documentation/admin-guide/index.rst b/Documentation/admin-guide/index.rst index 5bb9161dbe6a31be54992d412945289ce3a57587..78f8f00c369f22795016f875a3ace7db9c48950f 100644 --- a/Documentation/admin-guide/index.rst +++ b/Documentation/admin-guide/index.rst @@ -17,6 +17,15 @@ etc. kernel-parameters devices +This section describes CPU vulnerabilities and provides an overview of the +possible mitigations along with guidance for selecting mitigations if they +are configurable at compile, boot or run time. + +.. toctree:: + :maxdepth: 1 + + l1tf + Here is a set of documents aimed at users who are trying to track down problems and bugs in particular. diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 0613573ed177d8eb7c7dc35c4c09fd89f6338462..6af44985a48d625f9af4128ba65d01a633f50229 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -1897,10 +1897,84 @@ (virtualized real and unpaged mode) on capable Intel chips. Default is 1 (enabled) + kvm-intel.vmentry_l1d_flush=[KVM,Intel] Mitigation for L1 Terminal Fault + CVE-2018-3620. + + Valid arguments: never, cond, always + + always: L1D cache flush on every VMENTER. + cond: Flush L1D on VMENTER only when the code between + VMEXIT and VMENTER can leak host memory. + never: Disables the mitigation + + Default is cond (do L1 cache flush in specific instances) + kvm-intel.vpid= [KVM,Intel] Disable Virtual Processor Identification feature (tagged TLBs) on capable Intel chips. Default is 1 (enabled) + l1tf= [X86] Control mitigation of the L1TF vulnerability on + affected CPUs + + The kernel PTE inversion protection is unconditionally + enabled and cannot be disabled. + + full + Provides all available mitigations for the + L1TF vulnerability. Disables SMT and + enables all mitigations in the + hypervisors, i.e. unconditional L1D flush. + + SMT control and L1D flush control via the + sysfs interface is still possible after + boot. Hypervisors will issue a warning + when the first VM is started in a + potentially insecure configuration, + i.e. SMT enabled or L1D flush disabled. + + full,force + Same as 'full', but disables SMT and L1D + flush runtime control. Implies the + 'nosmt=force' command line option. + (i.e. sysfs control of SMT is disabled.) + + flush + Leaves SMT enabled and enables the default + hypervisor mitigation, i.e. conditional + L1D flush. + + SMT control and L1D flush control via the + sysfs interface is still possible after + boot. Hypervisors will issue a warning + when the first VM is started in a + potentially insecure configuration, + i.e. SMT enabled or L1D flush disabled. + + flush,nosmt + + Disables SMT and enables the default + hypervisor mitigation. + + SMT control and L1D flush control via the + sysfs interface is still possible after + boot. Hypervisors will issue a warning + when the first VM is started in a + potentially insecure configuration, + i.e. SMT enabled or L1D flush disabled. + + flush,nowarn + Same as 'flush', but hypervisors will not + warn when a VM is started in a potentially + insecure configuration. + + off + Disables hypervisor mitigations and doesn't + emit any warnings. + + Default is 'flush'. + + For details see: Documentation/admin-guide/l1tf.rst + l2cr= [PPC] l3cr= [PPC] @@ -2604,6 +2678,10 @@ nosmt [KNL,S390] Disable symmetric multithreading (SMT). Equivalent to smt=1. + [KNL,x86] Disable symmetric multithreading (SMT). + nosmt=force: Force disable SMT, cannot be undone + via the sysfs control file. + 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 diff --git a/Documentation/admin-guide/l1tf.rst b/Documentation/admin-guide/l1tf.rst new file mode 100644 index 0000000000000000000000000000000000000000..bae52b845de0b93af644ea55103d5a912dfca753 --- /dev/null +++ b/Documentation/admin-guide/l1tf.rst @@ -0,0 +1,610 @@ +L1TF - L1 Terminal Fault +======================== + +L1 Terminal Fault is a hardware vulnerability which allows unprivileged +speculative access to data which is available in the Level 1 Data Cache +when the page table entry controlling the virtual address, which is used +for the access, has the Present bit cleared or other reserved bits set. + +Affected processors +------------------- + +This vulnerability affects a wide range of Intel processors. The +vulnerability is not present on: + + - Processors from AMD, Centaur and other non Intel vendors + + - Older processor models, where the CPU family is < 6 + + - A range of Intel ATOM processors (Cedarview, Cloverview, Lincroft, + Penwell, Pineview, Silvermont, Airmont, Merrifield) + + - The Intel XEON PHI family + + - Intel processors which have the ARCH_CAP_RDCL_NO bit set in the + IA32_ARCH_CAPABILITIES MSR. If the bit is set the CPU is not affected + by the Meltdown vulnerability either. These CPUs should become + available by end of 2018. + +Whether a processor is affected or not can be read out from the L1TF +vulnerability file in sysfs. See :ref:`l1tf_sys_info`. + +Related CVEs +------------ + +The following CVE entries are related to the L1TF vulnerability: + + ============= ================= ============================== + CVE-2018-3615 L1 Terminal Fault SGX related aspects + CVE-2018-3620 L1 Terminal Fault OS, SMM related aspects + CVE-2018-3646 L1 Terminal Fault Virtualization related aspects + ============= ================= ============================== + +Problem +------- + +If an instruction accesses a virtual address for which the relevant page +table entry (PTE) has the Present bit cleared or other reserved bits set, +then speculative execution ignores the invalid PTE and loads the referenced +data if it is present in the Level 1 Data Cache, as if the page referenced +by the address bits in the PTE was still present and accessible. + +While this is a purely speculative mechanism and the instruction will raise +a page fault when it is retired eventually, the pure act of loading the +data and making it available to other speculative instructions opens up the +opportunity for side channel attacks to unprivileged malicious code, +similar to the Meltdown attack. + +While Meltdown breaks the user space to kernel space protection, L1TF +allows to attack any physical memory address in the system and the attack +works across all protection domains. It allows an attack of SGX and also +works from inside virtual machines because the speculation bypasses the +extended page table (EPT) protection mechanism. + + +Attack scenarios +---------------- + +1. Malicious user space +^^^^^^^^^^^^^^^^^^^^^^^ + + Operating Systems store arbitrary information in the address bits of a + PTE which is marked non present. This allows a malicious user space + application to attack the physical memory to which these PTEs resolve. + In some cases user-space can maliciously influence the information + encoded in the address bits of the PTE, thus making attacks more + deterministic and more practical. + + The Linux kernel contains a mitigation for this attack vector, PTE + inversion, which is permanently enabled and has no performance + impact. The kernel ensures that the address bits of PTEs, which are not + marked present, never point to cacheable physical memory space. + + A system with an up to date kernel is protected against attacks from + malicious user space applications. + +2. Malicious guest in a virtual machine +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + The fact that L1TF breaks all domain protections allows malicious guest + OSes, which can control the PTEs directly, and malicious guest user + space applications, which run on an unprotected guest kernel lacking the + PTE inversion mitigation for L1TF, to attack physical host memory. + + A special aspect of L1TF in the context of virtualization is symmetric + multi threading (SMT). The Intel implementation of SMT is called + HyperThreading. The fact that Hyperthreads on the affected processors + share the L1 Data Cache (L1D) is important for this. As the flaw allows + only to attack data which is present in L1D, a malicious guest running + on one Hyperthread can attack the data which is brought into the L1D by + the context which runs on the sibling Hyperthread of the same physical + core. This context can be host OS, host user space or a different guest. + + If the processor does not support Extended Page Tables, the attack is + only possible, when the hypervisor does not sanitize the content of the + effective (shadow) page tables. + + While solutions exist to mitigate these attack vectors fully, these + mitigations are not enabled by default in the Linux kernel because they + can affect performance significantly. The kernel provides several + mechanisms which can be utilized to address the problem depending on the + deployment scenario. The mitigations, their protection scope and impact + are described in the next sections. + + The default mitigations and the rationale for choosing them are explained + at the end of this document. See :ref:`default_mitigations`. + +.. _l1tf_sys_info: + +L1TF system information +----------------------- + +The Linux kernel provides a sysfs interface to enumerate the current L1TF +status of the system: whether the system is vulnerable, and which +mitigations are active. The relevant sysfs file is: + +/sys/devices/system/cpu/vulnerabilities/l1tf + +The possible values in this file are: + + =========================== =============================== + 'Not affected' The processor is not vulnerable + 'Mitigation: PTE Inversion' The host protection is active + =========================== =============================== + +If KVM/VMX is enabled and the processor is vulnerable then the following +information is appended to the 'Mitigation: PTE Inversion' part: + + - SMT status: + + ===================== ================ + 'VMX: SMT vulnerable' SMT is enabled + 'VMX: SMT disabled' SMT is disabled + ===================== ================ + + - L1D Flush mode: + + ================================ ==================================== + 'L1D vulnerable' L1D flushing is disabled + + 'L1D conditional cache flushes' L1D flush is conditionally enabled + + 'L1D cache flushes' L1D flush is unconditionally enabled + ================================ ==================================== + +The resulting grade of protection is discussed in the following sections. + + +Host mitigation mechanism +------------------------- + +The kernel is unconditionally protected against L1TF attacks from malicious +user space running on the host. + + +Guest mitigation mechanisms +--------------------------- + +.. _l1d_flush: + +1. L1D flush on VMENTER +^^^^^^^^^^^^^^^^^^^^^^^ + + To make sure that a guest cannot attack data which is present in the L1D + the hypervisor flushes the L1D before entering the guest. + + Flushing the L1D evicts not only the data which should not be accessed + by a potentially malicious guest, it also flushes the guest + data. Flushing the L1D has a performance impact as the processor has to + bring the flushed guest data back into the L1D. Depending on the + frequency of VMEXIT/VMENTER and the type of computations in the guest + performance degradation in the range of 1% to 50% has been observed. For + scenarios where guest VMEXIT/VMENTER are rare the performance impact is + minimal. Virtio and mechanisms like posted interrupts are designed to + confine the VMEXITs to a bare minimum, but specific configurations and + application scenarios might still suffer from a high VMEXIT rate. + + The kernel provides two L1D flush modes: + - conditional ('cond') + - unconditional ('always') + + The conditional mode avoids L1D flushing after VMEXITs which execute + only audited code paths before the corresponding VMENTER. These code + paths have been verified that they cannot expose secrets or other + interesting data to an attacker, but they can leak information about the + address space layout of the hypervisor. + + Unconditional mode flushes L1D on all VMENTER invocations and provides + maximum protection. It has a higher overhead than the conditional + mode. The overhead cannot be quantified correctly as it depends on the + workload scenario and the resulting number of VMEXITs. + + The general recommendation is to enable L1D flush on VMENTER. The kernel + defaults to conditional mode on affected processors. + + **Note**, that L1D flush does not prevent the SMT problem because the + sibling thread will also bring back its data into the L1D which makes it + attackable again. + + L1D flush can be controlled by the administrator via the kernel command + line and sysfs control files. See :ref:`mitigation_control_command_line` + and :ref:`mitigation_control_kvm`. + +.. _guest_confinement: + +2. Guest VCPU confinement to dedicated physical cores +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + To address the SMT problem, it is possible to make a guest or a group of + guests affine to one or more physical cores. The proper mechanism for + that is to utilize exclusive cpusets to ensure that no other guest or + host tasks can run on these cores. + + If only a single guest or related guests run on sibling SMT threads on + the same physical core then they can only attack their own memory and + restricted parts of the host memory. + + Host memory is attackable, when one of the sibling SMT threads runs in + host OS (hypervisor) context and the other in guest context. The amount + of valuable information from the host OS context depends on the context + which the host OS executes, i.e. interrupts, soft interrupts and kernel + threads. The amount of valuable data from these contexts cannot be + declared as non-interesting for an attacker without deep inspection of + the code. + + **Note**, that assigning guests to a fixed set of physical cores affects + the ability of the scheduler to do load balancing and might have + negative effects on CPU utilization depending on the hosting + scenario. Disabling SMT might be a viable alternative for particular + scenarios. + + For further information about confining guests to a single or to a group + of cores consult the cpusets documentation: + + https://www.kernel.org/doc/Documentation/cgroup-v1/cpusets.txt + +.. _interrupt_isolation: + +3. Interrupt affinity +^^^^^^^^^^^^^^^^^^^^^ + + Interrupts can be made affine to logical CPUs. This is not universally + true because there are types of interrupts which are truly per CPU + interrupts, e.g. the local timer interrupt. Aside of that multi queue + devices affine their interrupts to single CPUs or groups of CPUs per + queue without allowing the administrator to control the affinities. + + Moving the interrupts, which can be affinity controlled, away from CPUs + which run untrusted guests, reduces the attack vector space. + + Whether the interrupts with are affine to CPUs, which run untrusted + guests, provide interesting data for an attacker depends on the system + configuration and the scenarios which run on the system. While for some + of the interrupts it can be assumed that they won't expose interesting + information beyond exposing hints about the host OS memory layout, there + is no way to make general assumptions. + + Interrupt affinity can be controlled by the administrator via the + /proc/irq/$NR/smp_affinity[_list] files. Limited documentation is + available at: + + https://www.kernel.org/doc/Documentation/IRQ-affinity.txt + +.. _smt_control: + +4. SMT control +^^^^^^^^^^^^^^ + + To prevent the SMT issues of L1TF it might be necessary to disable SMT + completely. Disabling SMT can have a significant performance impact, but + the impact depends on the hosting scenario and the type of workloads. + The impact of disabling SMT needs also to be weighted against the impact + of other mitigation solutions like confining guests to dedicated cores. + + The kernel provides a sysfs interface to retrieve the status of SMT and + to control it. It also provides a kernel command line interface to + control SMT. + + The kernel command line interface consists of the following options: + + =========== ========================================================== + nosmt Affects the bring up of the secondary CPUs during boot. The + kernel tries to bring all present CPUs online during the + boot process. "nosmt" makes sure that from each physical + core only one - the so called primary (hyper) thread is + activated. Due to a design flaw of Intel processors related + to Machine Check Exceptions the non primary siblings have + to be brought up at least partially and are then shut down + again. "nosmt" can be undone via the sysfs interface. + + nosmt=force Has the same effect as "nosmt" but it does not allow to + undo the SMT disable via the sysfs interface. + =========== ========================================================== + + The sysfs interface provides two files: + + - /sys/devices/system/cpu/smt/control + - /sys/devices/system/cpu/smt/active + + /sys/devices/system/cpu/smt/control: + + This file allows to read out the SMT control state and provides the + ability to disable or (re)enable SMT. The possible states are: + + ============== =================================================== + on SMT is supported by the CPU and enabled. All + logical CPUs can be onlined and offlined without + restrictions. + + off SMT is supported by the CPU and disabled. Only + the so called primary SMT threads can be onlined + and offlined without restrictions. An attempt to + online a non-primary sibling is rejected + + forceoff Same as 'off' but the state cannot be controlled. + Attempts to write to the control file are rejected. + + notsupported The processor does not support SMT. It's therefore + not affected by the SMT implications of L1TF. + Attempts to write to the control file are rejected. + ============== =================================================== + + The possible states which can be written into this file to control SMT + state are: + + - on + - off + - forceoff + + /sys/devices/system/cpu/smt/active: + + This file reports whether SMT is enabled and active, i.e. if on any + physical core two or more sibling threads are online. + + SMT control is also possible at boot time via the l1tf kernel command + line parameter in combination with L1D flush control. See + :ref:`mitigation_control_command_line`. + +5. Disabling EPT +^^^^^^^^^^^^^^^^ + + Disabling EPT for virtual machines provides full mitigation for L1TF even + with SMT enabled, because the effective page tables for guests are + managed and sanitized by the hypervisor. Though disabling EPT has a + significant performance impact especially when the Meltdown mitigation + KPTI is enabled. + + EPT can be disabled in the hypervisor via the 'kvm-intel.ept' parameter. + +There is ongoing research and development for new mitigation mechanisms to +address the performance impact of disabling SMT or EPT. + +.. _mitigation_control_command_line: + +Mitigation control on the kernel command line +--------------------------------------------- + +The kernel command line allows to control the L1TF mitigations at boot +time with the option "l1tf=". The valid arguments for this option are: + + ============ ============================================================= + full Provides all available mitigations for the L1TF + vulnerability. Disables SMT and enables all mitigations in + the hypervisors, i.e. unconditional L1D flushing + + SMT control and L1D flush control via the sysfs interface + is still possible after boot. Hypervisors will issue a + warning when the first VM is started in a potentially + insecure configuration, i.e. SMT enabled or L1D flush + disabled. + + full,force Same as 'full', but disables SMT and L1D flush runtime + control. Implies the 'nosmt=force' command line option. + (i.e. sysfs control of SMT is disabled.) + + flush Leaves SMT enabled and enables the default hypervisor + mitigation, i.e. conditional L1D flushing + + SMT control and L1D flush control via the sysfs interface + is still possible after boot. Hypervisors will issue a + warning when the first VM is started in a potentially + insecure configuration, i.e. SMT enabled or L1D flush + disabled. + + flush,nosmt Disables SMT and enables the default hypervisor mitigation, + i.e. conditional L1D flushing. + + SMT control and L1D flush control via the sysfs interface + is still possible after boot. Hypervisors will issue a + warning when the first VM is started in a potentially + insecure configuration, i.e. SMT enabled or L1D flush + disabled. + + flush,nowarn Same as 'flush', but hypervisors will not warn when a VM is + started in a potentially insecure configuration. + + off Disables hypervisor mitigations and doesn't emit any + warnings. + ============ ============================================================= + +The default is 'flush'. For details about L1D flushing see :ref:`l1d_flush`. + + +.. _mitigation_control_kvm: + +Mitigation control for KVM - module parameter +------------------------------------------------------------- + +The KVM hypervisor mitigation mechanism, flushing the L1D cache when +entering a guest, can be controlled with a module parameter. + +The option/parameter is "kvm-intel.vmentry_l1d_flush=". It takes the +following arguments: + + ============ ============================================================== + always L1D cache flush on every VMENTER. + + cond Flush L1D on VMENTER only when the code between VMEXIT and + VMENTER can leak host memory which is considered + interesting for an attacker. This still can leak host memory + which allows e.g. to determine the hosts address space layout. + + never Disables the mitigation + ============ ============================================================== + +The parameter can be provided on the kernel command line, as a module +parameter when loading the modules and at runtime modified via the sysfs +file: + +/sys/module/kvm_intel/parameters/vmentry_l1d_flush + +The default is 'cond'. If 'l1tf=full,force' is given on the kernel command +line, then 'always' is enforced and the kvm-intel.vmentry_l1d_flush +module parameter is ignored and writes to the sysfs file are rejected. + + +Mitigation selection guide +-------------------------- + +1. No virtualization in use +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + The system is protected by the kernel unconditionally and no further + action is required. + +2. Virtualization with trusted guests +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + If the guest comes from a trusted source and the guest OS kernel is + guaranteed to have the L1TF mitigations in place the system is fully + protected against L1TF and no further action is required. + + To avoid the overhead of the default L1D flushing on VMENTER the + administrator can disable the flushing via the kernel command line and + sysfs control files. See :ref:`mitigation_control_command_line` and + :ref:`mitigation_control_kvm`. + + +3. Virtualization with untrusted guests +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +3.1. SMT not supported or disabled +"""""""""""""""""""""""""""""""""" + + If SMT is not supported by the processor or disabled in the BIOS or by + the kernel, it's only required to enforce L1D flushing on VMENTER. + + Conditional L1D flushing is the default behaviour and can be tuned. See + :ref:`mitigation_control_command_line` and :ref:`mitigation_control_kvm`. + +3.2. EPT not supported or disabled +"""""""""""""""""""""""""""""""""" + + If EPT is not supported by the processor or disabled in the hypervisor, + the system is fully protected. SMT can stay enabled and L1D flushing on + VMENTER is not required. + + EPT can be disabled in the hypervisor via the 'kvm-intel.ept' parameter. + +3.3. SMT and EPT supported and active +""""""""""""""""""""""""""""""""""""" + + If SMT and EPT are supported and active then various degrees of + mitigations can be employed: + + - L1D flushing on VMENTER: + + L1D flushing on VMENTER is the minimal protection requirement, but it + is only potent in combination with other mitigation methods. + + Conditional L1D flushing is the default behaviour and can be tuned. See + :ref:`mitigation_control_command_line` and :ref:`mitigation_control_kvm`. + + - Guest confinement: + + Confinement of guests to a single or a group of physical cores which + are not running any other processes, can reduce the attack surface + significantly, but interrupts, soft interrupts and kernel threads can + still expose valuable data to a potential attacker. See + :ref:`guest_confinement`. + + - Interrupt isolation: + + Isolating the guest CPUs from interrupts can reduce the attack surface + further, but still allows a malicious guest to explore a limited amount + of host physical memory. This can at least be used to gain knowledge + about the host address space layout. The interrupts which have a fixed + affinity to the CPUs which run the untrusted guests can depending on + the scenario still trigger soft interrupts and schedule kernel threads + which might expose valuable information. See + :ref:`interrupt_isolation`. + +The above three mitigation methods combined can provide protection to a +certain degree, but the risk of the remaining attack surface has to be +carefully analyzed. For full protection the following methods are +available: + + - Disabling SMT: + + Disabling SMT and enforcing the L1D flushing provides the maximum + amount of protection. This mitigation is not depending on any of the + above mitigation methods. + + SMT control and L1D flushing can be tuned by the command line + parameters 'nosmt', 'l1tf', 'kvm-intel.vmentry_l1d_flush' and at run + time with the matching sysfs control files. See :ref:`smt_control`, + :ref:`mitigation_control_command_line` and + :ref:`mitigation_control_kvm`. + + - Disabling EPT: + + Disabling EPT provides the maximum amount of protection as well. It is + not depending on any of the above mitigation methods. SMT can stay + enabled and L1D flushing is not required, but the performance impact is + significant. + + EPT can be disabled in the hypervisor via the 'kvm-intel.ept' + parameter. + +3.4. Nested virtual machines +"""""""""""""""""""""""""""" + +When nested virtualization is in use, three operating systems are involved: +the bare metal hypervisor, the nested hypervisor and the nested virtual +machine. VMENTER operations from the nested hypervisor into the nested +guest will always be processed by the bare metal hypervisor. If KVM is the +bare metal hypervisor it wiil: + + - Flush the L1D cache on every switch from the nested hypervisor to the + nested virtual machine, so that the nested hypervisor's secrets are not + exposed to the nested virtual machine; + + - Flush the L1D cache on every switch from the nested virtual machine to + the nested hypervisor; this is a complex operation, and flushing the L1D + cache avoids that the bare metal hypervisor's secrets are exposed to the + nested virtual machine; + + - Instruct the nested hypervisor to not perform any L1D cache flush. This + is an optimization to avoid double L1D flushing. + + +.. _default_mitigations: + +Default mitigations +------------------- + + The kernel default mitigations for vulnerable processors are: + + - PTE inversion to protect against malicious user space. This is done + unconditionally and cannot be controlled. + + - L1D conditional flushing on VMENTER when EPT is enabled for + a guest. + + The kernel does not by default enforce the disabling of SMT, which leaves + SMT systems vulnerable when running untrusted guests with EPT enabled. + + The rationale for this choice is: + + - Force disabling SMT can break existing setups, especially with + unattended updates. + + - If regular users run untrusted guests on their machine, then L1TF is + just an add on to other malware which might be embedded in an untrusted + guest, e.g. spam-bots or attacks on the local network. + + There is no technical way to prevent a user from running untrusted code + on their machines blindly. + + - It's technically extremely unlikely and from today's knowledge even + impossible that L1TF can be exploited via the most popular attack + mechanisms like JavaScript because these mechanisms have no way to + control PTEs. If this would be possible and not other mitigation would + be possible, then the default might be different. + + - The administrators of cloud and hosting setups have to carefully + analyze the risk for their scenarios and make the appropriate + mitigation choices, which might even vary across their deployed + machines and also result in other changes of their overall setup. + There is no way for the kernel to provide a sensible default for this + kind of scenarios. diff --git a/Documentation/blockdev/zram.txt b/Documentation/blockdev/zram.txt index 257e65714c6a216f3fce9ebce7398eb821f96176..b81c2d4a2167e4b36215fc0fe51fd3eadb0cfb2e 100644 --- a/Documentation/blockdev/zram.txt +++ b/Documentation/blockdev/zram.txt @@ -169,7 +169,7 @@ comp_algorithm RW show and change the compression algorithm compact WO trigger memory compaction debug_stat RO this file is used for zram debugging purposes backing_dev RW set up backend storage for zram to write out - +use_dedup RW show and set deduplication feature User space is advised to use the following files to read the device statistics. @@ -218,6 +218,8 @@ line of text and contains the following stats separated by whitespace: same_pages the number of same element filled pages written to this disk. No memory is allocated for such pages. pages_compacted the number of pages freed during compaction + dup_data_size deduplicated data size + meta_data_size the amount of metadata allocated for deduplication feature 9) Deactivate: swapoff /dev/zram0 diff --git a/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt b/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt index 72e279abc8f69ccbce6cdb06e94a975585c2054f..531ff1f6e4face83fe9c63e38586c15ace103b14 100644 --- a/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt +++ b/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt @@ -6,7 +6,7 @@ to be reset. Required Properties: - compatible: The bus devices need to be compatible with - "qcom,ext-mdm9x55", qcom,ext-sdx50m. + "qcom,ext-mdm9x55", qcom,ext-sdx50m, qcom,ext-sdxprairie. Required named gpio properties: - qcom,mdm2ap-errfatal-gpio: gpio for the external modem to indicate to the apps processor diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt index aa7a5e16f0d70b408d336894fa481b4cc65ad79e..2dd881518a6d0cd066aec04f9095e59082b19992 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm.txt @@ -62,6 +62,9 @@ SoCs: - SDMMAGPIE compatible = "qcom,sdmmagpie" +- TRINKET + compatible = "qcom,trinket" + Generic board variants: - CDP device: @@ -172,6 +175,9 @@ compatible = "qcom,qcs403-iot" compatible = "qcom,sa8155-adp-star" compatible = "qcom,sa8155p-adp-star" compatible = "qcom,adp-star" +compatible = "qcom,sa8155-v2-adp-air" +compatible = "qcom,sa8155p-v2-adp-air" +compatible = "qcom,adp-air" compatible = "qcom,sdxprairie-rumi" compatible = "qcom,sdxprairie-mtp" compatible = "qcom,sdxprairie-cdp" @@ -181,3 +187,4 @@ compatible = "qcom,sdmmagpie-qrd" compatible = "qcom,sdmmagpiep-idp" compatible = "qcom,sdmmagpiep" compatible = "qcom,sdmmagpiep-qrd" +compatible = "qcom,trinket-rumi" diff --git a/Documentation/devicetree/bindings/arm/msm/msm_aop_ddr_msgs.txt b/Documentation/devicetree/bindings/arm/msm/msm_aop_ddr_msgs.txt new file mode 100644 index 0000000000000000000000000000000000000000..de4160ae1a47914906be06b78eea04eed9a4278b --- /dev/null +++ b/Documentation/devicetree/bindings/arm/msm/msm_aop_ddr_msgs.txt @@ -0,0 +1,18 @@ +AOP (Always-On-Processor) DDR Related Messaging + +The AOP DDR messaging driver is used to send messages to the AOP, +using the mailbox interface, to lower the DDR frequency during reboot. + +Required properties + +- compatible : "qcom,aop-ddr-msgs" +- mbox : QMP mailbox phandle and channel identifier + +Optional properties: +-mbox-name: name of the mailbox + +Example: + qcom,aop-ddr-msgs { + compatible = "qcom,aop-ddr-msgs"; + mboxes = <&qmp_aop 0>; + }; diff --git a/Documentation/devicetree/bindings/bus/mhi.txt b/Documentation/devicetree/bindings/bus/mhi.txt index 837c33cd07481189a9a9dcfaf590703ff29f4890..34dff2203c0ab8384d4015180b47f97c349f5099 100644 --- a/Documentation/devicetree/bindings/bus/mhi.txt +++ b/Documentation/devicetree/bindings/bus/mhi.txt @@ -291,11 +291,6 @@ MHI netdev properties Value type: Definition: Interface name to be given so clients can identify it -- mhi,recycle-buf - Usage: optional - Value type: - Definition: Set true if interface support recycling buffers. - - aliases Usage: required Value type: diff --git a/Documentation/devicetree/bindings/clock/qcom,debugcc.txt b/Documentation/devicetree/bindings/clock/qcom,debugcc.txt index e8db516b35633cbafdaddd6fbc5f85cad55971cd..8e88ee435a10e9d1fddabcde79fa24bd8ffd2a27 100644 --- a/Documentation/devicetree/bindings/clock/qcom,debugcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,debugcc.txt @@ -5,7 +5,8 @@ Required properties : - compatible: Shall contain "qcom,debugcc-sm8150", "qcom,debugcc-qcs405", "qcom,debugcc-sm6150", - "qcom,debugcc-sdmmagpie". + "qcom,debugcc-sdmmagpie" + "qcom,debugcc-sdxprairie". - qcom,gcc: phandle to the GCC device node. - qcom,videocc: phandle to the Video CC device node. - qcom,camcc: phandle to the Camera CC device node. diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt index fd4f1f10f3ab3aeb429aa01e85329d60b7b7ac57..3f5087692ccfa928abb590b6dd692ed070102049 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt +++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt @@ -25,6 +25,7 @@ Required properties : "qcom,gcc-mdss-qcs405" "qcom,gcc-sm6150" "qcom,gcc-sdmmagpie" + "qcom,gcc-sdxprairie" - reg : shall contain base register location and length - #clock-cells : shall contain 1 diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmh.txt b/Documentation/devicetree/bindings/clock/qcom,rpmh.txt index db9fc37009122234ad44ad43287651a5d5574148..ece6b9e5b769e413ceae8a7ceeb2eb9bc34ece96 100644 --- a/Documentation/devicetree/bindings/clock/qcom,rpmh.txt +++ b/Documentation/devicetree/bindings/clock/qcom,rpmh.txt @@ -5,7 +5,8 @@ Required properties: "qcom,rpmh-clk-sm6150", "qcom,rpmh-clk-sm8150", "qcom,rpmh-clk-sdmshrike", - "qcom,rpmh-clk-sdmmagpie". + "qcom,rpmh-clk-sdmmagpie" + "qcom,rpmh-clk-sdxprairie". - #clock-cells: Must contain 1. - mboxes: List of RPMh mailbox phandle and channel identifier tuples. - mbox-names: List of names to identify the RPMh mailboxes used. diff --git a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt index 43c9d0bbe06d1fa2417d81a593716b78fd7529dc..db573bad96216509dc36dfe533b522dae84f95e1 100644 --- a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt +++ b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt @@ -187,6 +187,9 @@ Optional properties: 255 = default value. - qcom,mdss-brightness-max-level: Specifies the max brightness level supported. 255 = default value. +- qcom,bl-update-flag: A string that specifies controls for backlight update of the panel. + "delay_until_first_frame" = Delay backlight update of the panel + until the first frame is received from the HW. - qcom,mdss-dsi-interleave-mode: Specifies interleave mode. 0 = default value. - qcom,mdss-dsi-panel-type: Specifies the panel operating mode. @@ -529,6 +532,8 @@ Optional properties: display. The first set is indexed by the value 0. - qcom,mdss-dsi-ext-bridge-mode: External bridge chip is connected instead of panel. +- qcom,mdss-dsi-dma-schedule-line: An integer value indicates the line number after vertical active + region, at which command DMA needs to be triggered. Required properties for sub-nodes: None Optional properties: @@ -604,6 +609,7 @@ Example: qcom,mdss-dsi-bl-min-level = <1>; qcom,mdss-dsi-bl-max-level = < 15>; qcom,mdss-brightness-max-level = <255>; + qcom,bl-update-flag = "delay_until_first_frame"; qcom,mdss-dsi-interleave-mode = <0>; qcom,mdss-dsi-panel-type = "dsi_video_mode"; qcom,mdss-dsi-te-check-enable; @@ -786,5 +792,6 @@ Example: qcom,display-topology = <1 1 1>, <2 2 1>; qcom,default-topology-index = <0>; + qcom,mdss-dsi-dma-schedule-line = <5>; }; }; diff --git a/Documentation/devicetree/bindings/fb/mdss-pll.txt b/Documentation/devicetree/bindings/fb/mdss-pll.txt index d1e79295bc3f3b93607cb9c7501e12eb63b30ad2..18d5518e338e7b9d009c344a5e73d2e42653693d 100644 --- a/Documentation/devicetree/bindings/fb/mdss-pll.txt +++ b/Documentation/devicetree/bindings/fb/mdss-pll.txt @@ -19,7 +19,7 @@ Required properties: "qcom,mdss_hdmi_pll_8998", "qcom,mdss_dp_pll_10nm", "qcom,mdss_dsi_pll_7nm", "qcom,mdss_dp_pll_7nm", "qcom,mdss_dsi_pll_28lpm", "qcom,mdss_dsi_pll_14nm", - "qcom,mdss_dp_pll_14nm" + "qcom,mdss_dp_pll_14nm", "qcom,mdss_hdmi_pll_28lpm" - cell-index: Specifies the controller used - reg: offset and length of the register set for the device. - reg-names : names to refer to register sets related to this device diff --git a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt index 285a14f7ff6918ecafec26df5a737f85a2a38f2f..28eb6c14e34e173fb2abf1c3379854e9c36cf16f 100644 --- a/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt +++ b/Documentation/devicetree/bindings/fb/msm-hdmi-tx.txt @@ -47,6 +47,7 @@ Optional properties: HDMI interface will remain powered on from LK to kernel with continuous display of bootup logo. - qcom,pluggable: boolean to enable hotplug feature. +- qcom,max-pclk-frequency-khz: maximum supported pclk frequency in KHz. - qcom,display-id: A string indicates the display ID for the controller. The possible values are: - "primary" diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt index cf84dba7fece7d55aafcd6a2909e4a3cc50f3886..5e374fb6a9b1f2da85d1bb3283d89e7384849478 100644 --- a/Documentation/devicetree/bindings/gpu/adreno.txt +++ b/Documentation/devicetree/bindings/gpu/adreno.txt @@ -6,8 +6,9 @@ Required properties: - label: A string used as a descriptive name for the device. - compatible: Must be "qcom,kgsl-3d0" and "qcom,kgsl-3d" - reg: Specifies the register base address and size, the shader memory - base address and size (if it exists), and the base address and size - of the CX_DBGC block (if it exists). + base address and size (if it exists), base address and size + of the CX_DBGC block (if it exists), and the base address and + size of the CX_MISC block (if it exists). - reg-names: Resource names used for the physical address of device registers and shader memory. "kgsl_3d0_reg_memory" gives the physical address and length of device registers while "kgsl_3d0_shader_memory" gives @@ -15,7 +16,8 @@ Required properties: specified, "qfprom_memory" gives the range for the efuse registers used for various configuration options. If specified, "kgsl_3d0_cx_dbgc_memory" gives the physical address and length - of the CX DBGC block. + of the CX DBGC block. If specified, "cx_misc" gives + the physical address and length of the CX_MISC block. - interrupts: Interrupt mapping for GPU IRQ. - interrupt-names: String property to describe the name of the interrupt. - qcom,id: An integer used as an identification number for the device. @@ -85,6 +87,8 @@ DCVS Core info Optional Properties: - qcom,initial-powerlevel: This value indicates which qcom,gpu-pwrlevel should be used at start time and when coming back out of resume +- qcom,throttle-pwrlevel: This value indicates which qcom,gpu-pwrlevel LM throttling + may start to occur - qcom,bus-control: Boolean. Enables an independent bus vote from the gpu frequency - qcom,bus-width: Bus width in number of bytes. This enables dynamic AB bus voting based on bus width and actual bus transactions. diff --git a/Documentation/devicetree/bindings/interrupt-controller/qti,pdc-sdmmagpie.txt b/Documentation/devicetree/bindings/interrupt-controller/qti,pdc-sdmmagpie.txt deleted file mode 100644 index 968019c5ad99ac6bbc8cb62d5f4a3edde690ff9e..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/interrupt-controller/qti,pdc-sdmmagpie.txt +++ /dev/null @@ -1,63 +0,0 @@ -QTI PDC interrupt controller - -PDC is QTI's platform parent interrupt controller that serves as wakeup source. - -Newer QTI SOCs are replacing MPM (MSM sleep Power Manager) with PDC (Power -Domain Controller) to manage subsystem wakeups and resources during sleep. -This driver marks the wakeup interrupts in APSS PDC such that it monitors the -interrupts when the system is asleep, wakes up the APSS when one of these -interrupts occur and replays it to the subsystem interrupt controller after it -becomes operational. - -Earlier MPM architecture used arch-extension of GIC interrupt -controller to mark enabled wake-up interrupts and monitor these when the -system goes to sleep. Since the arch-extensions are no-longer available -on newer kernel versions, this driver is implemented as hierarchical irq -domain. GIC is parent interrupt controller at the highest level. -Platform interrupt controller PDC is next in hierarchy, followed by others. -This driver only configures the interrupts, does not handle them. - -PDC interrupt configuration involves programming of 2 set of registers: -IRQ_ENABLE_BANK - Enable the irq -IRQ_i_CFG - Configure the interrupt i - -Properties: - -- compatible: - Usage: required - Value type: - Definition: Should contain "qcom,pdc-" - -- reg: - Usage: required - Value type: - Definition: Specifies the base physical address for PDC hardware - block for DRV2. - -- interrupt-cells: - Usage: required - Value type: - Definition: Specifies the number of cells needed to encode an interrupt source. - Value must be 3. - The encoding of these cells are same as described in - Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt - -- interrupt-parent: - Usage: required - Value type: - Definition: Specifies the interrupt parent necessary for hierarchical domain to operate. - -- interrupt-controller: - Usage: required - Value type: - Definition: Identifies the node as an interrupt controller. - -Example: - -pdcgic: interrupt-controller@0xb220000{ - compatible = "qcom,pdc-sdmmagpie"; - reg = <0xb220000 0x30000>; - #interrupt-cells = <3>; - interrupt-parent = <&intc>; - interrupt-controller; -}; diff --git a/Documentation/devicetree/bindings/interrupt-controller/qti,pdc-sm6150.txt b/Documentation/devicetree/bindings/interrupt-controller/qti,pdc-sm6150.txt deleted file mode 100644 index 4ee8ae29f7ea388ce6aa114bc63a3e6c2ca11a77..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/interrupt-controller/qti,pdc-sm6150.txt +++ /dev/null @@ -1,63 +0,0 @@ -QTI PDC interrupt controller - -PDC is QTI's platform parent interrupt controller that serves as wakeup source. - -Newer QTI SOCs are replacing MPM (MSM sleep Power Manager) with PDC (Power -Domain Controller) to manage subsystem wakeups and resources during sleep. -This driver marks the wakeup interrupts in APSS PDC such that it monitors the -interrupts when the system is asleep, wakes up the APSS when one of these -interrupts occur and replays it to the subsystem interrupt controller after it -becomes operational. - -Earlier MPM architecture used arch-extension of GIC interrupt -controller to mark enabled wake-up interrupts and monitor these when the -system goes to sleep. Since the arch-extensions are no-longer available -on newer kernel versions, this driver is implemented as hierarchical irq -domain. GIC is parent interrupt controller at the highest level. -Platform interrupt controller PDC is next in hierarchy, followed by others. -This driver only configures the interrupts, does not handle them. - -PDC interrupt configuration involves programming of 2 set of registers: -IRQ_ENABLE_BANK - Enable the irq -IRQ_i_CFG - Configure the interrupt i - -Properties: - -- compatible: - Usage: required - Value type: - Definition: Should contain "qcom,pdc-" - -- reg: - Usage: required - Value type: - Definition: Specifies the base physical address for PDC hardware - block for DRV2. - -- interrupt-cells: - Usage: required - Value type: - Definition: Specifies the number of cells needed to encode an interrupt source. - Value must be 3. - The encoding of these cells are same as described in - Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt - -- interrupt-parent: - Usage: required - Value type: - Definition: Specifies the interrupt parent necessary for hierarchical domain to operate. - -- interrupt-controller: - Usage: required - Value type: - Definition: Identifies the node as an interrupt controller. - -Example: - -pdcgic: interrupt-controller@0xb220000{ - compatible = "qcom,pdc-sm6150"; - reg = <0xb220000 0x30000>; - #interrupt-cells = <3>; - interrupt-parent = <&intc>; - interrupt-controller; -}; diff --git a/Documentation/devicetree/bindings/interrupt-controller/qti,pdc-sm8150.txt b/Documentation/devicetree/bindings/interrupt-controller/qti,pdc-sm8150.txt deleted file mode 100644 index a254571874c2e2972bbbdf5e88cd95a6d807eebe..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/interrupt-controller/qti,pdc-sm8150.txt +++ /dev/null @@ -1,63 +0,0 @@ -QTI PDC interrupt controller - -PDC is QTI's platform parent interrupt controller that serves as wakeup source. - -Newer QTI SOCs are replacing MPM (MSM sleep Power Manager) with PDC (Power -Domain Controller) to manage subsystem wakeups and resources during sleep. -This driver marks the wakeup interrupts in APSS PDC such that it monitors the -interrupts when the system is asleep, wakes up the APSS when one of these -interrupts occur and replays it to the subsystem interrupt controller after it -becomes operational. - -Earlier MPM architecture used arch-extension of GIC interrupt -controller to mark enabled wake-up interrupts and monitor these when the -system goes to sleep. Since the arch-extensions are no-longer available -on newer kernel versions, this driver is implemented as hierarchical irq -domain. GIC is parent interrupt controller at the highest level. -Platform interrupt controller PDC is next in hierarchy, followed by others. -This driver only configures the interrupts, does not handle them. - -PDC interrupt configuration involves programming of 2 set of registers: -IRQ_ENABLE_BANK - Enable the irq -IRQ_i_CFG - Configure the interrupt i - -Properties: - -- compatible: - Usage: required - Value type: - Definition: Should contain "qcom,pdc-" - -- reg: - Usage: required - Value type: - Definition: Specifies the base physical address for PDC hardware - block for DRV2. - -- interrupt-cells: - Usage: required - Value type: - Definition: Specifies the number of cells needed to encode an interrupt source. - Value must be 3. - The encoding of these cells are same as described in - Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt - -- interrupt-parent: - Usage: required - Value type: - Definition: Specifies the interrupt parent necessary for hierarchical domain to operate. - -- interrupt-controller: - Usage: required - Value type: - Definition: Identifies the node as an interrupt controller. - -Example: - -pdcgic: interrupt-controller@0xb220000{ - compatible = "qcom,pdc-sm8150"; - reg = <0xb220000 0x30000>; - #interrupt-cells = <3>; - interrupt-parent = <&intc>; - interrupt-controller; -}; diff --git a/Documentation/devicetree/bindings/interrupt-controller/qti,pdc.txt b/Documentation/devicetree/bindings/interrupt-controller/qti,pdc.txt index 8598d0c963836cb836b6e32d9e0c9746087688a7..e6c0b3e87b8f18c7a53a91d4bc25b2cde5aa8167 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/qti,pdc.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/qti,pdc.txt @@ -26,7 +26,12 @@ Properties: - compatible: Usage: required Value type: - Definition: Should contain "qcom,pdc-" + Definition: Should contain one of - + "qcom,pdc-sdm845", + "qcom,pdc-sdmmagpie", + "qcom,pdc-sm6150", + "qcom,pdc-sm8150", + "qcom,pdc-sdxprairie", - reg: Usage: required diff --git a/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.txt b/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.txt index 26072d6fbca6466a1315044624aceb36f27809c0..03643e8ea194687f1c5654aac3adf3700b2b8fda 100644 --- a/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.txt +++ b/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.txt @@ -11,7 +11,9 @@ platforms. "qcom,msm8916-apcs-kpss-global", "qcom,msm8996-apcs-hmss-global", "qcom,sm8150-apcs-hmss-global", - "qcom,sm8150-spcs-global" + "qcom,sm8150-spcs-global", + "qcom,sdxprairie-apcs-gcc" + "qcom,trinket-apcs-hmss-global" - reg: Usage: required Value type: diff --git a/Documentation/devicetree/bindings/media/video/msm-vidc.txt b/Documentation/devicetree/bindings/media/video/msm-vidc.txt index cef1fe76443a038266fa0ed701ca7f2e442e2cb5..b1e6a504733cf615a2622b3a930abd6f23c847eb 100644 --- a/Documentation/devicetree/bindings/media/video/msm-vidc.txt +++ b/Documentation/devicetree/bindings/media/video/msm-vidc.txt @@ -9,6 +9,7 @@ Required properties: - "qcom,sm6150-vidc" : Invokes driver specific data for SM6150. - "qcom,sm8150-vidc" : Invokes driver specific data for SM8150. - "qcom,sm6150-vidc" : Invokes driver specific data for SM6150. + - "qcom,sdmmagpie-vidc" : Invokes driver specific data for sdmmagpie. - "qcom,sdm845-vidc" : Invokes driver specific data for SDM845. - "qcom,sdm670-vidc" : Invokes driver specific data for SDM670. diff --git a/Documentation/devicetree/bindings/pci/msm_pcie_msi.txt b/Documentation/devicetree/bindings/pci/msm_pcie_msi.txt new file mode 100644 index 0000000000000000000000000000000000000000..032db937915211ec4e4f89e01f0e25159ee19b21 --- /dev/null +++ b/Documentation/devicetree/bindings/pci/msm_pcie_msi.txt @@ -0,0 +1,69 @@ +* MSM PCIe MSI controller + +- compatible: + Usage: required + Value type: + Definition: Value to identify this is a MSM PCIe MSI controller + +- msi-controller: + Usage: required + Value type: + Definition: Indicates that this is a MSM PCIe MSI controller node + +- reg: + Usage: required + Value type: + Definition: Physical QGIC address (0x17a00040), MSI message address + +-interrupt-parent: + Usage: required + Value type: + Definition: Phandle of the interrupt controller that services + interrupts for this device + +-interrupts: + Usage: required + Value type: + Definition: Array of tuples which describe interrupt lines for PCIe MSI + +======= +Example +======= +pci_msi: qcom,pci_msi { + compatible = "qcom,pci-msi"; + msi-controller; + reg = <0x17a00040 0x0 0x0 0x0 0xff>; + interrupt-parent = <&pdc>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; +}; diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,qcs405-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,qcs405-pinctrl.txt index 10b8699132f2e31dca10c125c24a5c8960e3d36b..3f2834a5e712575f4c2ef5b278e6dc63786f50fa 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,qcs405-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/qcom,qcs405-pinctrl.txt @@ -11,7 +11,13 @@ QCS405 platform. - reg: Usage: required Value type: - Definition: the base address and size of the TLMM register space. + Definition: the base address and size of the TLMM register space + provided as "pinctrl". + +- reg-names: + Usage: required + Value type: + Definition: Provides labels for the reg property. - interrupts: Usage: required diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sdmmagpie-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,sdmmagpie-pinctrl.txt index 9f629b8ab82372969da8137a5bb446585564efe2..1858b4bd4f693a9252a47c40f18010164d49910d 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sdmmagpie-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sdmmagpie-pinctrl.txt @@ -11,7 +11,14 @@ SDMMAGPIE platform. - reg: Usage: required Value type: - Definition: the base address and size of the TLMM register space. + Definition: the base address and size of the TLMM register space + provided as "pinctrl" and optional base address + of shared SPI config registers provided as "spi_cfg". + +- reg-names: + Usage: required + Value type: + Definition: Provides labels for the reg property. - interrupts: Usage: required diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sdmshrike-pinctrl b/Documentation/devicetree/bindings/pinctrl/qcom,sdmshrike-pinctrl index e7ad14a2c1182b1a197c8db15bd629aa5d4ea18d..d5836db5ec7f08712e01682ede9219f52cf6c2c7 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sdmshrike-pinctrl +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sdmshrike-pinctrl @@ -11,7 +11,14 @@ sdmshrike platform. - reg: Usage: required Value type: - Definition: the base address and size of the TLMM register space. + Definition: the base address and size of the TLMM register space + provided as "pinctrl" and optional base address + of shared SPI config registers provided as "spi_cfg". + +- reg-names: + Usage: required + Value type: + Definition: Provides labels for the reg property. - interrupts: Usage: required diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sdxprairie-pinctrl b/Documentation/devicetree/bindings/pinctrl/qcom,sdxprairie-pinctrl index 9de6959b0aa67fc62ce15e8bb9e0fe7b4f2d632f..e09faf303503f5c393f31d2dce8bad1905aea5b9 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sdxprairie-pinctrl +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sdxprairie-pinctrl @@ -11,7 +11,14 @@ SDXPRAIRIE platform. - reg: Usage: required Value type: - Definition: the base address and size of the TLMM register space. + Definition: the base address and size of the TLMM register space + provided as "pinctrl" and optional base address + of PDC mux selection registers provided as "pdc". + +- reg-names: + Usage: required + Value type: + Definition: Provides labels for the reg property. - interrupts: Usage: required diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm6150-pinctrl b/Documentation/devicetree/bindings/pinctrl/qcom,sm6150-pinctrl index 9787c416f8d903bb61e832dd474d95bc06d54865..30fe7bdc947e8e8b0320ccd41b9aa617ff2c8f01 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm6150-pinctrl +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm6150-pinctrl @@ -11,7 +11,14 @@ SM6150 platform. - reg: Usage: required Value type: - Definition: the base address and size of the TLMM register space. + Definition: the base address and size of the TLMM register space + provided as "pinctrl" and optional base address + of shared SPI config registers provided as "spi_cfg". + +- reg-names: + Usage: required + Value type: + Definition: Provides labels for the reg property. - interrupts: Usage: required @@ -111,7 +118,7 @@ to specify in a pin configuration subnode: qdss_tracectl_a, dac_calib13, qdss_traceclk_a, dac_calib14, dac_calib15, hdmi_rcv, dac_calib16, hdmi_cec, pwr_modem, dac_calib17, hdmi_ddc, pwr_nav, dac_calib18, pwr_crypto, - dac_calib19, hdmi_hot, dac_calib20, dac_calib21, pci_e0, + dac_calib19, hdmi_hot, dac_calib20, dac_calib21, pcie_ep, dac_calib22, dac_calib23, dac_calib24, tsif1_sync, dac_calib25, sd_write, tsif1_error, blsp_spi2, blsp_uart2, blsp_uim2, qdss_cti, blsp_i2c2, blsp_spi3, blsp_uart3, blsp_uim3, blsp_i2c3, @@ -133,10 +140,9 @@ to specify in a pin configuration subnode: sd_card, tsif2_data, sdc41, tsif2_sync, sdc40, mdp_vsync_p_b, ldo_en, mdp_vsync_s_b, ldo_update, blsp11_uart_tx_b, blsp11_uart_rx_b, blsp11_i2c_sda_b, prng_rosc, blsp11_i2c_scl_b, uim2, uim1, uim_batt, - pci_e2, pa_indicator, adsp_ext, ddr_bist, qdss_tracedata_11, - qdss_tracedata_12, modem_tsync, nav_dr, nav_pps, pci_e1, gsm_tx, - qspi_cs, ssbi2, ssbi1, mss_lte, qspi_clk, qspi0, qspi1, qspi2, qspi3, - gpio + pcie_clk, pa_indicator, adsp_ext, ddr_bist, qdss_tracedata_11, + qdss_tracedata_12, modem_tsync, nav_dr, nav_pps, gsm_tx, qspi_cs, + ssbi2, ssbi1, mss_lte, qspi_clk, qspi0, qspi1, qspi2, qspi3, gpio - bias-disable: Usage: optional diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8150-pinctrl b/Documentation/devicetree/bindings/pinctrl/qcom,sm8150-pinctrl index fd3090837cfb0fd5807d08c02e838d55bda0989f..64fef96c75d666155d7a0b448515e369accbf413 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8150-pinctrl +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8150-pinctrl @@ -11,7 +11,14 @@ SM8150 platform. - reg: Usage: required Value type: - Definition: the base address and size of the TLMM register space. + Definition: the base address and size of the TLMM register space + provided as "pinctrl" and optional base address + of shared SPI config registers provided as "spi_cfg". + +- reg-names: + Usage: required + Value type: + Definition: Provides labels for the reg property. - interrupts: Usage: required diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,trinket-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,trinket-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..893fbd9880d01bffed1304c032914fc5da880adc --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/qcom,trinket-pinctrl.txt @@ -0,0 +1,187 @@ +Qualcomm Technologies, Inc. TRINKET TLMM block + +This binding describes the Top Level Mode Multiplexer block found in the +TRINKET platform. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,trinket-pinctrl" + +- reg: + Usage: required + Value type: + Definition: the base address and size of the TLMM register space. + +- interrupts: + Usage: required + Value type: + Definition: should specify the TLMM summary IRQ. + +- interrupt-controller: + Usage: required + Value type: + Definition: identifies this node as an interrupt controller + +- #interrupt-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- gpio-controller: + Usage: required + Value type: + Definition: identifies this node as a gpio controller + +- #gpio-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + + +PIN CONFIGURATION NODES: + + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +- pins: + Usage: required + Value type: + Definition: List of gpio pins affected by the properties specified in + this subnode. + + Valid pins are: + gpio0-gpio132 + Supports mux, bias and drive-strength + + sdc1_clk, sdc1_cmd, sdc1_data sdc2_clk, sdc2_cmd, + sdc2_data sdc1_rclk + Supports bias and drive-strength + +- function: + Usage: required + Value type: + Definition: Specify the alternative function to be configured for the + specified pins. Functions are only valid for gpio pins. + Valid values are: + + blsp_uart1, blsp_spi1, blsp_i2c1, blsp_uim1, atest_tsens, + bimc_dte1, dac_calib0, blsp_spi8, blsp_uart8, blsp_uim8, + qdss_cti_trig_out_b, bimc_dte0, dac_calib1, qdss_cti_trig_in_b, + dac_calib2, atest_tsens2, atest_usb1, blsp_spi10, blsp_uart10, + blsp_uim10, atest_bbrx1, atest_usb13, atest_bbrx0, atest_usb12, + mdp_vsync, edp_lcd, blsp_i2c10, atest_gpsadc1, atest_usb11, + atest_gpsadc0, edp_hot, atest_usb10, m_voc, dac_gpio, atest_char, + cam_mclk, pll_bypassnl, qdss_stm7, blsp_i2c8, qdss_tracedata_b, + pll_reset, qdss_stm6, qdss_stm5, qdss_stm4, atest_usb2, cci_i2c, + qdss_stm3, dac_calib3, atest_usb23, atest_char3, dac_calib4, + qdss_stm2, atest_usb22, atest_char2, qdss_stm1, dac_calib5, + atest_usb21, atest_char1, dbg_out, qdss_stm0, dac_calib6, + atest_usb20, atest_char0, dac_calib10, qdss_stm10, + qdss_cti_trig_in_a, cci_timer4, blsp_spi6, blsp_uart6, blsp_uim6, + blsp2_spi, qdss_stm9, qdss_cti_trig_out_a, dac_calib11, + qdss_stm8, cci_timer0, qdss_stm13, dac_calib7, cci_timer1, + qdss_stm12, dac_calib8, cci_timer2, blsp1_spi, qdss_stm11, + dac_calib9, cci_timer3, cci_async, dac_calib12, blsp_i2c6, + qdss_tracectl_a, dac_calib13, qdss_traceclk_a, dac_calib14, + dac_calib15, hdmi_rcv, dac_calib16, hdmi_cec, pwr_modem, + dac_calib17, hdmi_ddc, pwr_nav, dac_calib18, pwr_crypto, + dac_calib19, hdmi_hot, dac_calib20, dac_calib21, pci_e0, + dac_calib22, dac_calib23, dac_calib24, tsif1_sync, dac_calib25, + sd_write, tsif1_error, blsp_spi2, blsp_uart2, blsp_uim2, + qdss_cti, blsp_i2c2, blsp_spi3, blsp_uart3, blsp_uim3, blsp_i2c3, + uim3, blsp_spi9, blsp_uart9, blsp_uim9, blsp10_spi, blsp_i2c9, + blsp_spi7, blsp_uart7, blsp_uim7, qdss_tracedata_a, blsp_i2c7, + qua_mi2s, gcc_gp1_clk_a, ssc_irq, uim4, blsp_spi11, blsp_uart11, + blsp_uim11, gcc_gp2_clk_a, gcc_gp3_clk_a, blsp_i2c11, cri_trng0, + cri_trng1, cri_trng, qdss_stm18, pri_mi2s, qdss_stm17, blsp_spi4, + blsp_uart4, blsp_uim4, qdss_stm16, qdss_stm15, blsp_i2c4, + qdss_stm14, dac_calib26, spkr_i2s, audio_ref, lpass_slimbus, + isense_dbg, tsense_pwm1, tsense_pwm2, btfm_slimbus, ter_mi2s, + qdss_stm22, qdss_stm21, qdss_stm20, qdss_stm19, gcc_gp1_clk_b, + sec_mi2s, blsp_spi5, blsp_uart5, blsp_uim5, gcc_gp2_clk_b, + gcc_gp3_clk_b, blsp_i2c5, blsp_spi12, blsp_uart12, blsp_uim12, + qdss_stm25, qdss_stm31, blsp_i2c12, qdss_stm30, qdss_stm29, + tsif1_clk, qdss_stm28, tsif1_en, tsif1_data, sdc4_cmd, qdss_stm27, + qdss_traceclk_b, tsif2_error, sdc43, vfr_1, qdss_stm26, tsif2_clk, + sdc4_clk, qdss_stm24, tsif2_en, sdc42, qdss_stm23, qdss_tracectl_b, + sd_card, tsif2_data, sdc41, tsif2_sync, sdc40, mdp_vsync_p_b, + ldo_en, mdp_vsync_s_b, ldo_update, blsp11_uart_tx_b, blsp11_uart_rx_b, + blsp11_i2c_sda_b, prng_rosc, blsp11_i2c_scl_b, uim2, uim1, uim_batt, + pci_e2, pa_indicator, adsp_ext, ddr_bist, qdss_tracedata_11, + qdss_tracedata_12, modem_tsync, nav_dr, nav_pps, pci_e1, gsm_tx, + qspi_cs, ssbi2, ssbi1, mss_lte, qspi_clk, qspi0, qspi1, qspi2, qspi3, + gpio + +- bias-disable: + Usage: optional + Value type: + Definition: The specified pins should be configued as no pull. + +- bias-pull-down: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull down. + +- bias-pull-up: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull up. + +- output-high: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + high. + Not valid for sdc pins. + +- output-low: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + low. + Not valid for sdc pins. + +- drive-strength: + Usage: optional + Value type: + Definition: Selects the drive strength for the specified pins, in mA. + Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16 + +Example: + + tlmm: pinctrl@400000 { + compatible = "qcom,trinket-pinctrl"; + reg = <0x400000 0xc00000>; + interrupts = <0 227 0>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen4.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen4.txt index b656f268c1a41fdaf8c246f25bcb5e1f8f50b4d2..1d6d9ab2afb0a8780c13f467c0a46aed75743843 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen4.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-fg-gen4.txt @@ -186,10 +186,8 @@ First Level Node - FG Gen4 device - qcom,fg-batt-temp-hyst Usage: optional Value type: - Definition: Battery temperature hysteresis threshold. This will be - applicable only if the cold and hot thresholds are - specified. Possible values are: 0, 1, 2 and 3. Unit is in - Kelvin or Celsius. + Definition: Battery temperature hysteresis threshold. Possible values + are: 0, 1, 2 and 3. Unit is in Kelvin or Celsius. - qcom,fg-force-load-profile Usage: optional @@ -368,6 +366,13 @@ First Level Node - FG Gen4 device decrease when the battery SOC is low but not converging to zero with battery voltage dropping rapidly below Vcutoff. +- qcom,five-pin-battery + Usage: optional + Value type: + Definition: A boolean property that when specified indicates that a + five pin battery is used. Based on this, time to full + calculations would use the Rbatt calculated properly. + ========================================================== Second Level Nodes - Peripherals managed by FG Gen4 driver ========================================================== diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt index 83f964d9d565c79b59b3f5e4e303c149e7755477..1e49e964244316bd7196acbc90c13ae3ab066bcf 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt @@ -308,6 +308,20 @@ First Level Node - QGAUGE device Definition: Boolean property to support external-rsense based configuration. +- qcom,shutdown-temp-diff + Usage: optional + Value type: + Definition: The allowed battery temperature in deci-degree difference + between shutdown and power-on to continue with the shutdown + SOC. If not specified the default value is 6 degrees C (60). + +- qcom,shutdown-soc-threshold + Usage: optional + Value type: + Definition: The SOC difference allowed between PON and SHUTDOWN SOC + for the shutdown SOC to be used. If the difference is + beyond this value the PON SOC is used. + ========================================================== Second Level Nodes - Peripherals managed by QGAUGE driver ========================================================== diff --git a/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt index e80b3b39c94de1de01e5adb6c4dcc4654a9af526..6fae4187b0522c0c72f92a341bd9740096007550 100644 --- a/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt @@ -31,6 +31,14 @@ First Level Node - LCDB module Value type: Definition: Phandle to the PMIC's revid node +- qcom,voltage-step-ramp + Usage: optional + Value type: + Definition: Required only if the voltage needs to be set in the + steps of 500 mV starting from the 4500 mV. This needs + to be enabled only on platforms where voltage needs to + be ramped up with multiple steps. + Touch-to-wake (TTW) properties: TTW supports 2 modes of operation - HW and SW. In the HW mode the enable/disable diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,msm-eud.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,msm-eud.txt index 800508afbf69df79f9d8c70e4e83aa74bff7c75c..08330ebe7b339fdf3f44a0383d77d59518ea6782 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,msm-eud.txt +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,msm-eud.txt @@ -11,6 +11,10 @@ Required properties: - reg: Should be address and size of EUD register space - reg-names: Should be "eud_base" +Optional properties: + - reg-names: Can be "eud_mode_mgr2" for secure eud + - qcom,secure-eud-en: To enable secure eud + Driver notifies clients via extcon for VBUS spoof attach/detach and charger enable/disable events. Clients registered for these notifications should have extcon property set to eud. diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smp2p.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,smp2p.txt index af9ca37221ceac6f33872d9ae4fa438cab435259..a35af2dafdad6a78b989f7a519f4887203a50735 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,smp2p.txt +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smp2p.txt @@ -17,9 +17,15 @@ processor ID) and a string identifier. Value type: Definition: one entry specifying the smp2p notification interrupt -- qcom,ipc: +- mboxes: Usage: required Value type: + Definition: reference to the associated doorbell in APCS, as described + in mailbox/mailbox.txt + +- qcom,ipc: + Usage: required, unless mboxes is specified + Value type: Definition: three entries specifying the outgoing ipc bit used for signaling the remote end of the smp2p edge: - phandle to a syscon node representing the apcs registers diff --git a/Documentation/devicetree/bindings/thermal/qcom,cx-ipeak-cdev.txt b/Documentation/devicetree/bindings/thermal/qcom,cx-ipeak-cdev.txt index 0792223f83fb495a2bbb10682fbb1a77add1b942..562cc6e5f5d36ad91fe9ecbdd1e7969731513ab6 100644 --- a/Documentation/devicetree/bindings/thermal/qcom,cx-ipeak-cdev.txt +++ b/Documentation/devicetree/bindings/thermal/qcom,cx-ipeak-cdev.txt @@ -18,6 +18,24 @@ Required Parameters: register address of the CX IPEAK LM hardware and 'b' is the size of the peripheral address space. +- qcom,thermal-client-offset: + Usage: Optional + Value type: + Definition: This property is required for CX IP LM v1.1 and above + hardware. Must contain offset from CX IPEAK LM reg + base for thermal client voting. If this property is not defined, + then CX IPEAK cooling device will use legacy CXIP LM hardware + offset registers. + +- qcom,bypass-client-list: + Usage: Optional + Value type: + Definition: This property is required for CX IP LM v1.1 and above + hardware. Must contain array of offsets from CX IPEAK LM reg + base for clients those are not participating voting to CXIP LM + hardware. This property makes sense only when thermal-client + is defined. + - #cooling-cells: Usage: required Value type: @@ -29,5 +47,7 @@ Example: cxip_cdev: cxip-cdev@1fed000 { compatible = "qcom,cxip-lm-cooling-device"; reg = <0x1fed000 0x24>; + qcom,thermal-client-offset = <0x8000>; + qcom,bypass-client-list = <0x2004 0x3004>; #cooling-cells = <2>; }; diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt index 36ac0d96faec311f67a6781a94670dc2120226a7..b0654130445f1447f1cab3f405f005e5f5233f9c 100644 --- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt +++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt @@ -82,6 +82,8 @@ Optional properties : - qcom,host-poweroff-in-pm-suspend: If present, allow PM suspend to happen irrespective of runtimePM state of host and power collapse the core. This also leads to reset-resume of connected devices on PM resume. +- qcom,default-mode-host: If present, start host mode on probe for an OTG + capable DWC3 which does not have extcon handle. Sub nodes: - Sub node for "DWC3- USB3 controller". diff --git a/Documentation/devicetree/bindings/usb/nxp5150a.txt b/Documentation/devicetree/bindings/usb/nxp5150a.txt new file mode 100644 index 0000000000000000000000000000000000000000..30e0cf29435c0a6d776c7b3f30ea848bf98854d4 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/nxp5150a.txt @@ -0,0 +1,21 @@ +NXP PTN5150A - CC Logic chip for USB Type-C applications + +Required properties: +- compatible: should contain "nxp,5150a" +- reg: The device 7-bit I2C address +- interrupts: interrupt number that is used for interrupts from the device. + +Optional properties: +- vbus-out-gpio: gpio for enabling VBUS output (e.g. when entering host mode) + +Example device node: + +&i2c4 { + nxp_5150a: nxp5150a@1d { + compatbile = "nxp,5150a"; + reg = <0x1d>; + interrupt-parent = <&msm_gpio>; + interrupts = <35 2>; + vbus-out-gpio = <&msm_gpio 3 1>; + }; +}; diff --git a/Documentation/devicetree/bindings/usb/qcom,msm-phy.txt b/Documentation/devicetree/bindings/usb/qcom,msm-phy.txt index d87ab9f6d9d545bf50fb863eeabd68ce999965f6..137a6a0a09b117b0a20b1171dede9d6c607f129b 100644 --- a/Documentation/devicetree/bindings/usb/qcom,msm-phy.txt +++ b/Documentation/devicetree/bindings/usb/qcom,msm-phy.txt @@ -115,6 +115,9 @@ Optional properties: microvolts or a value corresponding to voltage corner. - qcom,link-training-reset: This property indicates to start link training timer to reset the elastic buffer based on rx equalization value. + - extcon : phandle to external connector devices which provide type-C based + "USB-HOST" cable events. This phandle is used for notifying number + of lanes used in case of USB+DP concurrent mode to driver. Example: ssphy0: ssphy@f9b38000 { diff --git a/Documentation/hwmon/ina2xx b/Documentation/hwmon/ina2xx index cfd31d94c8727251179a0c2afcc4f9b2a4580156..f8bf14055c2f38593b78d3c74545835080ba0c91 100644 --- a/Documentation/hwmon/ina2xx +++ b/Documentation/hwmon/ina2xx @@ -32,7 +32,7 @@ Supported chips: Datasheet: Publicly available at the Texas Instruments website http://www.ti.com/ -Author: Lothar Felten +Author: Lothar Felten Description ----------- diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 579337f3fbf3455f24d74d4ff2a1397d0faeac88..23064e9f7f126f7996debf9e523a4ee37039af2b 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -133,14 +133,11 @@ min_adv_mss - INTEGER IP Fragmentation: -ipfrag_high_thresh - INTEGER - Maximum memory used to reassemble IP fragments. When - ipfrag_high_thresh bytes of memory is allocated for this purpose, - the fragment handler will toss packets until ipfrag_low_thresh - is reached. This also serves as a maximum limit to namespaces - different from the initial one. - -ipfrag_low_thresh - INTEGER +ipfrag_high_thresh - LONG INTEGER + Maximum memory used to reassemble IP fragments. + +ipfrag_low_thresh - LONG INTEGER + (Obsolete since linux-4.17) Maximum memory used to reassemble IP fragments before the kernel begins to remove incomplete fragment queues to free up resources. The kernel still accepts new fragments for defragmentation. diff --git a/Documentation/process/changes.rst b/Documentation/process/changes.rst index 560beaef5a7c83b99b69292943a1eb2732efccee..73fcdcd52b879132872b6f8ad062a672dd68cf0f 100644 --- a/Documentation/process/changes.rst +++ b/Documentation/process/changes.rst @@ -33,7 +33,7 @@ GNU C 3.2 gcc --version GNU make 3.81 make --version binutils 2.20 ld -v util-linux 2.10o fdformat --version -module-init-tools 0.9.10 depmod -V +kmod 13 depmod -V e2fsprogs 1.41.4 e2fsck -V jfsutils 1.1.3 fsck.jfs -V reiserfsprogs 3.6.3 reiserfsck -V @@ -141,12 +141,6 @@ is not build with ``CONFIG_KALLSYMS`` and you have no way to rebuild and reproduce the Oops with that option, then you can still decode that Oops with ksymoops. -Module-Init-Tools ------------------ - -A new module loader is now in the kernel that requires ``module-init-tools`` -to use. It is backward compatible with the 2.4.x series kernels. - Mkinitrd -------- @@ -346,16 +340,17 @@ Util-linux - +Kmod +---- + +- +- + Ksymoops -------- - -Module-Init-Tools ------------------ - -- - Mkinitrd -------- diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 88ad78c6f605fb5967888f30b38c4021e0efc8ce..5d12166bd66b009f12b23b352baed949fd832d0a 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -123,14 +123,15 @@ memory layout to fit in user mode), check KVM_CAP_MIPS_VZ and use the flag KVM_VM_MIPS_VZ. -4.3 KVM_GET_MSR_INDEX_LIST +4.3 KVM_GET_MSR_INDEX_LIST, KVM_GET_MSR_FEATURE_INDEX_LIST -Capability: basic +Capability: basic, KVM_CAP_GET_MSR_FEATURES for KVM_GET_MSR_FEATURE_INDEX_LIST Architectures: x86 -Type: system +Type: system ioctl Parameters: struct kvm_msr_list (in/out) Returns: 0 on success; -1 on error Errors: + EFAULT: the msr index list cannot be read from or written to E2BIG: the msr index list is to be to fit in the array specified by the user. @@ -139,16 +140,23 @@ struct kvm_msr_list { __u32 indices[0]; }; -This ioctl returns the guest msrs that are supported. The list varies -by kvm version and host processor, but does not change otherwise. The -user fills in the size of the indices array in nmsrs, and in return -kvm adjusts nmsrs to reflect the actual number of msrs and fills in -the indices array with their numbers. +The user fills in the size of the indices array in nmsrs, and in return +kvm adjusts nmsrs to reflect the actual number of msrs and fills in the +indices array with their numbers. + +KVM_GET_MSR_INDEX_LIST returns the guest msrs that are supported. The list +varies by kvm version and host processor, but does not change otherwise. Note: if kvm indicates supports MCE (KVM_CAP_MCE), then the MCE bank MSRs are not returned in the MSR list, as different vcpus can have a different number of banks, as set via the KVM_X86_SETUP_MCE ioctl. +KVM_GET_MSR_FEATURE_INDEX_LIST returns the list of MSRs that can be passed +to the KVM_GET_MSRS system ioctl. This lets userspace probe host capabilities +and processor features that are exposed via MSRs (e.g., VMX capabilities). +This list also varies by kvm version and host processor, but does not change +otherwise. + 4.4 KVM_CHECK_EXTENSION @@ -475,14 +483,22 @@ Support for this has been removed. Use KVM_SET_GUEST_DEBUG instead. 4.18 KVM_GET_MSRS -Capability: basic +Capability: basic (vcpu), KVM_CAP_GET_MSR_FEATURES (system) Architectures: x86 -Type: vcpu ioctl +Type: system ioctl, vcpu ioctl Parameters: struct kvm_msrs (in/out) -Returns: 0 on success, -1 on error +Returns: number of msrs successfully returned; + -1 on error + +When used as a system ioctl: +Reads the values of MSR-based features that are available for the VM. This +is similar to KVM_GET_SUPPORTED_CPUID, but it returns MSR indices and values. +The list of msr-based features can be obtained using KVM_GET_MSR_FEATURE_INDEX_LIST +in a system ioctl. +When used as a vcpu ioctl: Reads model-specific registers from the vcpu. Supported msr indices can -be obtained using KVM_GET_MSR_INDEX_LIST. +be obtained using KVM_GET_MSR_INDEX_LIST in a system ioctl. struct kvm_msrs { __u32 nmsrs; /* number of msrs in entries */ diff --git a/Makefile b/Makefile index af8f68cb819850fba069d68a85c76716cf020296..344d4a68ae6343b86a87f47ef14cdbf565256f1d 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 14 -SUBLEVEL = 62 +SUBLEVEL = 76 EXTRAVERSION = NAME = Petit Gorille @@ -357,9 +357,9 @@ CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ else if [ -x /bin/bash ]; then echo /bin/bash; \ else echo sh; fi ; fi) -HOST_LFS_CFLAGS := $(shell getconf LFS_CFLAGS) -HOST_LFS_LDFLAGS := $(shell getconf LFS_LDFLAGS) -HOST_LFS_LIBS := $(shell getconf LFS_LIBS) +HOST_LFS_CFLAGS := $(shell getconf LFS_CFLAGS 2>/dev/null) +HOST_LFS_LDFLAGS := $(shell getconf LFS_LDFLAGS 2>/dev/null) +HOST_LFS_LIBS := $(shell getconf LFS_LIBS 2>/dev/null) HOSTCC = gcc HOSTCXX = g++ @@ -501,9 +501,13 @@ KBUILD_AFLAGS += $(CLANG_TARGET) $(CLANG_GCC_TC) endif RETPOLINE_CFLAGS_GCC := -mindirect-branch=thunk-extern -mindirect-branch-register +RETPOLINE_VDSO_CFLAGS_GCC := -mindirect-branch=thunk-inline -mindirect-branch-register RETPOLINE_CFLAGS_CLANG := -mretpoline-external-thunk +RETPOLINE_VDSO_CFLAGS_CLANG := -mretpoline RETPOLINE_CFLAGS := $(call cc-option,$(RETPOLINE_CFLAGS_GCC),$(call cc-option,$(RETPOLINE_CFLAGS_CLANG))) +RETPOLINE_VDSO_CFLAGS := $(call cc-option,$(RETPOLINE_VDSO_CFLAGS_GCC),$(call cc-option,$(RETPOLINE_VDSO_CFLAGS_CLANG))) export RETPOLINE_CFLAGS +export RETPOLINE_VDSO_CFLAGS ifeq ($(config-targets),1) # =========================================================================== diff --git a/arch/Kconfig b/arch/Kconfig index 6ba7bbb16c68ec99e2cc24cdc463f30d5257ef0a..0c9cdc875e95dcf1c67d095c7a6415cf60170a9a 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -13,6 +13,9 @@ config KEXEC_CORE config HAVE_IMA_KEXEC bool +config HOTPLUG_SMT + bool + config OPROFILE tristate "OProfile system profiling" depends on PROFILING @@ -333,6 +336,9 @@ config HAVE_ARCH_JUMP_LABEL config HAVE_RCU_TABLE_FREE bool +config HAVE_RCU_TABLE_INVALIDATE + bool + config ARCH_HAVE_NMI_SAFE_CMPXCHG bool diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index a48976dc9bcd0ad8638aadfd927e0480f3816c3e..918c3938ef6652a24c84edffeb5f3727afba23af 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -530,24 +530,19 @@ SYSCALL_DEFINE4(osf_mount, unsigned long, typenr, const char __user *, path, SYSCALL_DEFINE1(osf_utsname, char __user *, name) { int error; + char tmp[5 * 32]; down_read(&uts_sem); - error = -EFAULT; - if (copy_to_user(name + 0, utsname()->sysname, 32)) - goto out; - if (copy_to_user(name + 32, utsname()->nodename, 32)) - goto out; - if (copy_to_user(name + 64, utsname()->release, 32)) - goto out; - if (copy_to_user(name + 96, utsname()->version, 32)) - goto out; - if (copy_to_user(name + 128, utsname()->machine, 32)) - goto out; + memcpy(tmp + 0 * 32, utsname()->sysname, 32); + memcpy(tmp + 1 * 32, utsname()->nodename, 32); + memcpy(tmp + 2 * 32, utsname()->release, 32); + memcpy(tmp + 3 * 32, utsname()->version, 32); + memcpy(tmp + 4 * 32, utsname()->machine, 32); + up_read(&uts_sem); - error = 0; - out: - up_read(&uts_sem); - return error; + if (copy_to_user(name, tmp, sizeof(tmp))) + return -EFAULT; + return 0; } SYSCALL_DEFINE0(getpagesize) @@ -567,18 +562,21 @@ SYSCALL_DEFINE2(osf_getdomainname, char __user *, name, int, namelen) { int len, err = 0; char *kname; + char tmp[32]; - if (namelen > 32) + if (namelen < 0 || namelen > 32) namelen = 32; down_read(&uts_sem); kname = utsname()->domainname; len = strnlen(kname, namelen); - if (copy_to_user(name, kname, min(len + 1, namelen))) - err = -EFAULT; + len = min(len + 1, namelen); + memcpy(tmp, kname, len); up_read(&uts_sem); - return err; + if (copy_to_user(name, tmp, len)) + return -EFAULT; + return 0; } /* @@ -739,13 +737,14 @@ SYSCALL_DEFINE3(osf_sysinfo, int, command, char __user *, buf, long, count) }; unsigned long offset; const char *res; - long len, err = -EINVAL; + long len; + char tmp[__NEW_UTS_LEN + 1]; offset = command-1; if (offset >= ARRAY_SIZE(sysinfo_table)) { /* Digital UNIX has a few unpublished interfaces here */ printk("sysinfo(%d)", command); - goto out; + return -EINVAL; } down_read(&uts_sem); @@ -753,13 +752,11 @@ SYSCALL_DEFINE3(osf_sysinfo, int, command, char __user *, buf, long, count) len = strlen(res)+1; if ((unsigned long)len > (unsigned long)count) len = count; - if (copy_to_user(buf, res, len)) - err = -EFAULT; - else - err = 0; + memcpy(tmp, res, len); up_read(&uts_sem); - out: - return err; + if (copy_to_user(buf, tmp, len)) + return -EFAULT; + return 0; } SYSCALL_DEFINE5(osf_getsysinfo, unsigned long, op, void __user *, buffer, diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index 5c8caf85c35054722402d86f58033820d3de7640..8ff06609068038541f608df562170b3429193f6b 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -45,6 +45,9 @@ config ARC select HAVE_KERNEL_GZIP select HAVE_KERNEL_LZMA +config ARCH_HAS_CACHE_LINE_SIZE + def_bool y + config MIGHT_HAVE_PCI bool diff --git a/arch/arc/Makefile b/arch/arc/Makefile index d37f49d6a27f40f65d3e34bd3e2df5343a97d1e4..6c1b20dd76ad902655d7317eb44580923d98c690 100644 --- a/arch/arc/Makefile +++ b/arch/arc/Makefile @@ -16,7 +16,7 @@ endif KBUILD_DEFCONFIG := nsim_700_defconfig -cflags-y += -fno-common -pipe -fno-builtin -D__linux__ +cflags-y += -fno-common -pipe -fno-builtin -mmedium-calls -D__linux__ cflags-$(CONFIG_ISA_ARCOMPACT) += -mA7 cflags-$(CONFIG_ISA_ARCV2) += -mcpu=archs @@ -140,16 +140,3 @@ dtbs: scripts archclean: $(Q)$(MAKE) $(clean)=$(boot) - -# Hacks to enable final link due to absence of link-time branch relexation -# and gcc choosing optimal(shorter) branches at -O3 -# -# vineetg Feb 2010: -mlong-calls switched off for overall kernel build -# However lib/decompress_inflate.o (.init.text) calls -# zlib_inflate_workspacesize (.text) causing relocation errors. -# Thus forcing all exten calls in this file to be long calls -export CFLAGS_decompress_inflate.o = -mmedium-calls -export CFLAGS_initramfs.o = -mmedium-calls -ifdef CONFIG_SMP -export CFLAGS_core.o = -mmedium-calls -endif diff --git a/arch/arc/configs/axs101_defconfig b/arch/arc/configs/axs101_defconfig index a8242362e55199e550f4da319f1f5f2bd33f23c2..ece78630d71124cd1557cd987a3f6021c2383486 100644 --- a/arch/arc/configs/axs101_defconfig +++ b/arch/arc/configs/axs101_defconfig @@ -1,5 +1,4 @@ CONFIG_DEFAULT_HOSTNAME="ARCLinux" -# CONFIG_SWAP is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y # CONFIG_CROSS_MEMORY_ATTACH is not set diff --git a/arch/arc/configs/axs103_defconfig b/arch/arc/configs/axs103_defconfig index ef3c31cd77378c0fcfed9f4e97a05ba1460c5410..240c9251a7d4a19d7745fcb4aeafd1d26c657442 100644 --- a/arch/arc/configs/axs103_defconfig +++ b/arch/arc/configs/axs103_defconfig @@ -1,5 +1,4 @@ CONFIG_DEFAULT_HOSTNAME="ARCLinux" -# CONFIG_SWAP is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y # CONFIG_CROSS_MEMORY_ATTACH is not set diff --git a/arch/arc/configs/axs103_smp_defconfig b/arch/arc/configs/axs103_smp_defconfig index 1757ac9cecbc10fb189673d23a76ad5137e9ed9f..af54b96abee04a16c0eb65a2690c45c9edaee560 100644 --- a/arch/arc/configs/axs103_smp_defconfig +++ b/arch/arc/configs/axs103_smp_defconfig @@ -1,5 +1,4 @@ CONFIG_DEFAULT_HOSTNAME="ARCLinux" -# CONFIG_SWAP is not set CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y # CONFIG_CROSS_MEMORY_ATTACH is not set diff --git a/arch/arc/include/asm/atomic.h b/arch/arc/include/asm/atomic.h index 11859287c52af55df317e7a6d3ab9403706bd172..c98b59ac061230ad75e3d4ac61e1529a3fb46193 100644 --- a/arch/arc/include/asm/atomic.h +++ b/arch/arc/include/asm/atomic.h @@ -84,7 +84,7 @@ static inline int atomic_fetch_##op(int i, atomic_t *v) \ "1: llock %[orig], [%[ctr]] \n" \ " " #asm_op " %[val], %[orig], %[i] \n" \ " scond %[val], [%[ctr]] \n" \ - " \n" \ + " bnz 1b \n" \ : [val] "=&r" (val), \ [orig] "=&r" (orig) \ : [ctr] "r" (&v->counter), \ diff --git a/arch/arc/include/asm/cache.h b/arch/arc/include/asm/cache.h index 8486f328cc5d2aea087812ab19be949001e64b73..ff7d3232764a29a41503a213d3bd385e232acf42 100644 --- a/arch/arc/include/asm/cache.h +++ b/arch/arc/include/asm/cache.h @@ -48,7 +48,9 @@ }) /* Largest line length for either L1 or L2 is 128 bytes */ -#define ARCH_DMA_MINALIGN 128 +#define SMP_CACHE_BYTES 128 +#define cache_line_size() SMP_CACHE_BYTES +#define ARCH_DMA_MINALIGN SMP_CACHE_BYTES extern void arc_cache_init(void); extern char *arc_cache_mumbojumbo(int cpu_id, char *buf, int len); diff --git a/arch/arc/include/asm/delay.h b/arch/arc/include/asm/delay.h index d5da2115d78a678e343da2abec51f6c8efbbe0a4..03d6bb0f4e13a2dd49708f12dfb6f2f4788bf8ae 100644 --- a/arch/arc/include/asm/delay.h +++ b/arch/arc/include/asm/delay.h @@ -17,8 +17,11 @@ #ifndef __ASM_ARC_UDELAY_H #define __ASM_ARC_UDELAY_H +#include #include /* HZ */ +extern unsigned long loops_per_jiffy; + static inline void __delay(unsigned long loops) { __asm__ __volatile__( diff --git a/arch/arc/include/asm/mach_desc.h b/arch/arc/include/asm/mach_desc.h index c28e6c347b4900217ad48053c69679bb3da8b607..871f3cb16af9f2ec58c76192ffc098d914588b9d 100644 --- a/arch/arc/include/asm/mach_desc.h +++ b/arch/arc/include/asm/mach_desc.h @@ -34,9 +34,7 @@ struct machine_desc { const char *name; const char **dt_compat; void (*init_early)(void); -#ifdef CONFIG_SMP void (*init_per_cpu)(unsigned int); -#endif void (*init_machine)(void); void (*init_late)(void); diff --git a/arch/arc/kernel/irq.c b/arch/arc/kernel/irq.c index 538b36afe89e7c9871e2c37d2322d839a9b27a26..62b185057c040157132386aaee6ff56eaaebcf25 100644 --- a/arch/arc/kernel/irq.c +++ b/arch/arc/kernel/irq.c @@ -31,10 +31,10 @@ void __init init_IRQ(void) /* a SMP H/w block could do IPI IRQ request here */ if (plat_smp_ops.init_per_cpu) plat_smp_ops.init_per_cpu(smp_processor_id()); +#endif if (machine_desc->init_per_cpu) machine_desc->init_per_cpu(smp_processor_id()); -#endif } /* diff --git a/arch/arc/kernel/process.c b/arch/arc/kernel/process.c index 5ac3b547453fd5b4b5393fdc10dfff34a047941f..8ce6e723591556fc12765a19e08090632bb9d0ba 100644 --- a/arch/arc/kernel/process.c +++ b/arch/arc/kernel/process.c @@ -47,7 +47,8 @@ SYSCALL_DEFINE0(arc_gettls) SYSCALL_DEFINE3(arc_usr_cmpxchg, int *, uaddr, int, expected, int, new) { struct pt_regs *regs = current_pt_regs(); - int uval = -EFAULT; + u32 uval; + int ret; /* * This is only for old cores lacking LLOCK/SCOND, which by defintion @@ -60,23 +61,47 @@ SYSCALL_DEFINE3(arc_usr_cmpxchg, int *, uaddr, int, expected, int, new) /* Z indicates to userspace if operation succeded */ regs->status32 &= ~STATUS_Z_MASK; - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int))) - return -EFAULT; + ret = access_ok(VERIFY_WRITE, uaddr, sizeof(*uaddr)); + if (!ret) + goto fail; +again: preempt_disable(); - if (__get_user(uval, uaddr)) - goto done; + ret = __get_user(uval, uaddr); + if (ret) + goto fault; - if (uval == expected) { - if (!__put_user(new, uaddr)) - regs->status32 |= STATUS_Z_MASK; - } + if (uval != expected) + goto out; -done: - preempt_enable(); + ret = __put_user(new, uaddr); + if (ret) + goto fault; + + regs->status32 |= STATUS_Z_MASK; +out: + preempt_enable(); return uval; + +fault: + preempt_enable(); + + if (unlikely(ret != -EFAULT)) + goto fail; + + down_read(¤t->mm->mmap_sem); + ret = fixup_user_fault(current, current->mm, (unsigned long) uaddr, + FAULT_FLAG_WRITE, NULL); + up_read(¤t->mm->mmap_sem); + + if (likely(!ret)) + goto again; + +fail: + force_sig(SIGSEGV, current); + return ret; } #ifdef CONFIG_ISA_ARCV2 @@ -216,6 +241,26 @@ int copy_thread(unsigned long clone_flags, task_thread_info(current)->thr_ptr; } + + /* + * setup usermode thread pointer #1: + * when child is picked by scheduler, __switch_to() uses @c_callee to + * populate usermode callee regs: this works (despite being in a kernel + * function) since special return path for child @ret_from_fork() + * ensures those regs are not clobbered all the way to RTIE to usermode + */ + c_callee->r25 = task_thread_info(p)->thr_ptr; + +#ifdef CONFIG_ARC_CURR_IN_REG + /* + * setup usermode thread pointer #2: + * however for this special use of r25 in kernel, __switch_to() sets + * r25 for kernel needs and only in the final return path is usermode + * r25 setup, from pt_regs->user_r25. So set that up as well + */ + c_regs->user_r25 = c_callee->r25; +#endif + return 0; } diff --git a/arch/arc/mm/cache.c b/arch/arc/mm/cache.c index eee924dfffa6e1baf08221ee5e7e2cd23937d782..d14499500106df2fc25ac18d28425b62fa56086e 100644 --- a/arch/arc/mm/cache.c +++ b/arch/arc/mm/cache.c @@ -1035,7 +1035,7 @@ void flush_cache_mm(struct mm_struct *mm) void flush_cache_page(struct vm_area_struct *vma, unsigned long u_vaddr, unsigned long pfn) { - unsigned int paddr = pfn << PAGE_SHIFT; + phys_addr_t paddr = pfn << PAGE_SHIFT; u_vaddr &= PAGE_MASK; @@ -1055,8 +1055,9 @@ void flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long u_vaddr) { /* TBD: do we really need to clear the kernel mapping */ - __flush_dcache_page(page_address(page), u_vaddr); - __flush_dcache_page(page_address(page), page_address(page)); + __flush_dcache_page((phys_addr_t)page_address(page), u_vaddr); + __flush_dcache_page((phys_addr_t)page_address(page), + (phys_addr_t)page_address(page)); } diff --git a/arch/arc/plat-eznps/include/plat/ctop.h b/arch/arc/plat-eznps/include/plat/ctop.h index 0c7d11022d0f8875256e64162d2ee0f1f0aa85e1..4f6a1673b3a6eaacc80473108dec4cc8c1e4236c 100644 --- a/arch/arc/plat-eznps/include/plat/ctop.h +++ b/arch/arc/plat-eznps/include/plat/ctop.h @@ -21,6 +21,7 @@ #error "Incorrect ctop.h include" #endif +#include #include /* core auxiliary registers */ @@ -143,6 +144,15 @@ struct nps_host_reg_gim_p_int_dst { }; /* AUX registers definition */ +struct nps_host_reg_aux_dpc { + union { + struct { + u32 ien:1, men:1, hen:1, reserved:29; + }; + u32 value; + }; +}; + struct nps_host_reg_aux_udmc { union { struct { diff --git a/arch/arc/plat-eznps/mtm.c b/arch/arc/plat-eznps/mtm.c index 2388de3d09ef9e71f710ec4625e20a9e85cbdc1e..ed0077ef666eb7bdb8930bb2b52eddbe46f0b946 100644 --- a/arch/arc/plat-eznps/mtm.c +++ b/arch/arc/plat-eznps/mtm.c @@ -15,6 +15,8 @@ */ #include +#include +#include #include #include #include @@ -157,10 +159,10 @@ void mtm_enable_core(unsigned int cpu) /* Verify and set the value of the mtm hs counter */ static int __init set_mtm_hs_ctr(char *ctr_str) { - long hs_ctr; + int hs_ctr; int ret; - ret = kstrtol(ctr_str, 0, &hs_ctr); + ret = kstrtoint(ctr_str, 0, &hs_ctr); if (ret || hs_ctr > MT_HS_CNT_MAX || hs_ctr < MT_HS_CNT_MIN) { pr_err("** Invalid @nps_mtm_hs_ctr [%d] needs to be [%d:%d] (incl)\n", diff --git a/arch/arm/boot/dts/am3517.dtsi b/arch/arm/boot/dts/am3517.dtsi index 00da3f2c4072d4d6a3a370e88b1acfa046b58efd..4b57094a0356e1bb12c2aaef249228859344baea 100644 --- a/arch/arm/boot/dts/am3517.dtsi +++ b/arch/arm/boot/dts/am3517.dtsi @@ -87,6 +87,11 @@ }; }; +/* Table Table 5-79 of the TRM shows 480ab000 is reserved */ +&usb_otg_hs { + status = "disabled"; +}; + &iva { status = "disabled"; }; diff --git a/arch/arm/boot/dts/am437x-sk-evm.dts b/arch/arm/boot/dts/am437x-sk-evm.dts index 2c6bf0684f5055bfe014bd4e433f4cd035e0924a..094fd0ea91a03d1889e7d6fa7c55a61859e3f269 100644 --- a/arch/arm/boot/dts/am437x-sk-evm.dts +++ b/arch/arm/boot/dts/am437x-sk-evm.dts @@ -535,6 +535,8 @@ touchscreen-size-x = <480>; touchscreen-size-y = <272>; + + wakeup-source; }; tlv320aic3106: tlv320aic3106@1b { diff --git a/arch/arm/boot/dts/armada-385-synology-ds116.dts b/arch/arm/boot/dts/armada-385-synology-ds116.dts index 31510eb56f108e8a8708bb6e4a513fb137982c13..874189b4d21866e38a8c8960a66b4ef5916efd7e 100644 --- a/arch/arm/boot/dts/armada-385-synology-ds116.dts +++ b/arch/arm/boot/dts/armada-385-synology-ds116.dts @@ -170,7 +170,7 @@ 3700 5 3900 6 4000 7>; - cooling-cells = <2>; + #cooling-cells = <2>; }; gpio-leds { diff --git a/arch/arm/boot/dts/bcm-cygnus.dtsi b/arch/arm/boot/dts/bcm-cygnus.dtsi index 9a9902974b1b86d16c0a9e8280c0fa6da0de8222..8b2c65cd61a2951dd5e170b81c2230ce449d3cf0 100644 --- a/arch/arm/boot/dts/bcm-cygnus.dtsi +++ b/arch/arm/boot/dts/bcm-cygnus.dtsi @@ -216,7 +216,7 @@ reg = <0x18008000 0x100>; #address-cells = <1>; #size-cells = <0>; - interrupts = ; + interrupts = ; clock-frequency = <100000>; status = "disabled"; }; @@ -245,7 +245,7 @@ reg = <0x1800b000 0x100>; #address-cells = <1>; #size-cells = <0>; - interrupts = ; + interrupts = ; clock-frequency = <100000>; status = "disabled"; }; @@ -256,7 +256,7 @@ #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &gic GIC_SPI 100 IRQ_TYPE_NONE>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>; linux,pci-domain = <0>; @@ -278,10 +278,10 @@ compatible = "brcm,iproc-msi"; msi-controller; interrupt-parent = <&gic>; - interrupts = , - , - , - ; + interrupts = , + , + , + ; }; }; @@ -291,7 +291,7 @@ #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &gic GIC_SPI 106 IRQ_TYPE_NONE>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>; linux,pci-domain = <1>; @@ -313,10 +313,10 @@ compatible = "brcm,iproc-msi"; msi-controller; interrupt-parent = <&gic>; - interrupts = , - , - , - ; + interrupts = , + , + , + ; }; }; diff --git a/arch/arm/boot/dts/bcm-nsp.dtsi b/arch/arm/boot/dts/bcm-nsp.dtsi index d5f5e92e74889d25fbbc0a853ef9d3e0ea6e7bae..1792192001a22da9e563963d7c715e019d5accde 100644 --- a/arch/arm/boot/dts/bcm-nsp.dtsi +++ b/arch/arm/boot/dts/bcm-nsp.dtsi @@ -391,7 +391,7 @@ reg = <0x38000 0x50>; #address-cells = <1>; #size-cells = <0>; - interrupts = ; + interrupts = ; clock-frequency = <100000>; dma-coherent; status = "disabled"; @@ -496,7 +496,7 @@ #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &gic GIC_SPI 131 IRQ_TYPE_NONE>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>; linux,pci-domain = <0>; @@ -519,10 +519,10 @@ compatible = "brcm,iproc-msi"; msi-controller; interrupt-parent = <&gic>; - interrupts = , - , - , - ; + interrupts = , + , + , + ; brcm,pcie-msi-inten; }; }; @@ -533,7 +533,7 @@ #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &gic GIC_SPI 137 IRQ_TYPE_NONE>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>; linux,pci-domain = <1>; @@ -556,10 +556,10 @@ compatible = "brcm,iproc-msi"; msi-controller; interrupt-parent = <&gic>; - interrupts = , - , - , - ; + interrupts = , + , + , + ; brcm,pcie-msi-inten; }; }; @@ -570,7 +570,7 @@ #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &gic GIC_SPI 143 IRQ_TYPE_NONE>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>; linux,pci-domain = <2>; @@ -593,10 +593,10 @@ compatible = "brcm,iproc-msi"; msi-controller; interrupt-parent = <&gic>; - interrupts = , - , - , - ; + interrupts = , + , + , + ; brcm,pcie-msi-inten; }; }; diff --git a/arch/arm/boot/dts/bcm5301x.dtsi b/arch/arm/boot/dts/bcm5301x.dtsi index 045b9bb857f9a030491bc3bdbf82ae67bb841b73..501877e87a5b8fb2f1eb7341211c6215c1aa8be8 100644 --- a/arch/arm/boot/dts/bcm5301x.dtsi +++ b/arch/arm/boot/dts/bcm5301x.dtsi @@ -365,7 +365,7 @@ i2c0: i2c@18009000 { compatible = "brcm,iproc-i2c"; reg = <0x18009000 0x50>; - interrupts = ; + interrupts = ; #address-cells = <1>; #size-cells = <0>; clock-frequency = <100000>; diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi index 8a15f7193c829bcea8cda3553d0622a4c9222406..77dd62e260db682c457afc18d181d1b4466e685f 100644 --- a/arch/arm/boot/dts/da850.dtsi +++ b/arch/arm/boot/dts/da850.dtsi @@ -518,11 +518,7 @@ gpio-controller; #gpio-cells = <2>; reg = <0x226000 0x1000>; - interrupts = <42 IRQ_TYPE_EDGE_BOTH - 43 IRQ_TYPE_EDGE_BOTH 44 IRQ_TYPE_EDGE_BOTH - 45 IRQ_TYPE_EDGE_BOTH 46 IRQ_TYPE_EDGE_BOTH - 47 IRQ_TYPE_EDGE_BOTH 48 IRQ_TYPE_EDGE_BOTH - 49 IRQ_TYPE_EDGE_BOTH 50 IRQ_TYPE_EDGE_BOTH>; + interrupts = <42 43 44 45 46 47 48 49 50>; ti,ngpio = <144>; ti,davinci-gpio-unbanked = <0>; status = "disabled"; diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index 02a136a4661aa1ed172e4926a7a8dabad9e271b9..a5bd8f0205e8e58f719a519685e8709df431bfc9 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -1818,7 +1818,7 @@ }; }; - dcan1: can@481cc000 { + dcan1: can@4ae3c000 { compatible = "ti,dra7-d_can"; ti,hwmods = "dcan1"; reg = <0x4ae3c000 0x2000>; @@ -1828,7 +1828,7 @@ status = "disabled"; }; - dcan2: can@481d0000 { + dcan2: can@48480000 { compatible = "ti,dra7-d_can"; ti,hwmods = "dcan2"; reg = <0x48480000 0x2000>; diff --git a/arch/arm/boot/dts/imx6qdl-zii-rdu2.dtsi b/arch/arm/boot/dts/imx6qdl-zii-rdu2.dtsi index eeb7679fd348a4932d123a8bd7ec76fb5107cc63..849eb3443cde2712705bbbe6c74679ddb81095a8 100644 --- a/arch/arm/boot/dts/imx6qdl-zii-rdu2.dtsi +++ b/arch/arm/boot/dts/imx6qdl-zii-rdu2.dtsi @@ -644,7 +644,7 @@ dsa,member = <0 0>; eeprom-length = <512>; interrupt-parent = <&gpio6>; - interrupts = <3 IRQ_TYPE_EDGE_FALLING>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; interrupt-controller; #interrupt-cells = <2>; diff --git a/arch/arm/boot/dts/imx6sx.dtsi b/arch/arm/boot/dts/imx6sx.dtsi index 6c7eb54be9e2a4912d27cd4dcc2803a338390323..d64438bfa68b305c7dae6a4a5b42fe76e3f96caa 100644 --- a/arch/arm/boot/dts/imx6sx.dtsi +++ b/arch/arm/boot/dts/imx6sx.dtsi @@ -1305,7 +1305,7 @@ 0x82000000 0 0x08000000 0x08000000 0 0x00f00000>; bus-range = <0x00 0xff>; num-lanes = <1>; - interrupts = ; + interrupts = ; clocks = <&clks IMX6SX_CLK_PCIE_REF_125M>, <&clks IMX6SX_CLK_PCIE_AXI>, <&clks IMX6SX_CLK_LVDS1_OUT>, diff --git a/arch/arm/boot/dts/imx7d.dtsi b/arch/arm/boot/dts/imx7d.dtsi index 4d308d17f040c71157db72a8d81abf8de9dd4d8e..119b63ffb0fec4c55ef4c424343e032dd951da37 100644 --- a/arch/arm/boot/dts/imx7d.dtsi +++ b/arch/arm/boot/dts/imx7d.dtsi @@ -144,10 +144,14 @@ interrupt-names = "msi"; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0x7>; - interrupt-map = <0 0 0 1 &intc GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>, - <0 0 0 2 &intc GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>, - <0 0 0 3 &intc GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>, - <0 0 0 4 &intc GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>; + /* + * Reference manual lists pci irqs incorrectly + * Real hardware ordering is same as imx6: D+MSI, C, B, A + */ + interrupt-map = <0 0 0 1 &intc GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 2 &intc GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 3 &intc GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 4 &intc GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clks IMX7D_PCIE_CTRL_ROOT_CLK>, <&clks IMX7D_PLL_ENET_MAIN_100M_CLK>, <&clks IMX7D_PCIE_PHY_ROOT_CLK>; diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi index 379b4a03cfe2f7b92b2c3bd630d204be12a337d9..2d20f60947b951bd1181cef7326a76f82213f45c 100644 --- a/arch/arm/boot/dts/ls1021a.dtsi +++ b/arch/arm/boot/dts/ls1021a.dtsi @@ -84,6 +84,7 @@ device_type = "cpu"; reg = <0xf01>; clocks = <&clockgen 1 0>; + #cooling-cells = <2>; }; }; diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi index 1853573235724419002fd7617ddb9bf0e9a20fc3..028cf4a5887fcecdff631a2c922e2eec0776258d 100644 --- a/arch/arm/boot/dts/mt7623.dtsi +++ b/arch/arm/boot/dts/mt7623.dtsi @@ -98,6 +98,7 @@ compatible = "arm,cortex-a7"; reg = <0x1>; operating-points-v2 = <&cpu_opp_table>; + #cooling-cells = <2>; clock-frequency = <1300000000>; }; @@ -106,6 +107,7 @@ compatible = "arm,cortex-a7"; reg = <0x2>; operating-points-v2 = <&cpu_opp_table>; + #cooling-cells = <2>; clock-frequency = <1300000000>; }; @@ -114,6 +116,7 @@ compatible = "arm,cortex-a7"; reg = <0x3>; operating-points-v2 = <&cpu_opp_table>; + #cooling-cells = <2>; clock-frequency = <1300000000>; }; }; diff --git a/arch/arm/boot/dts/omap4-droid4-xt894.dts b/arch/arm/boot/dts/omap4-droid4-xt894.dts index 8b93d37310f28ba4c10ad81d35f8419914ef4633..bad690b23081bba82637ad6f05122da34a71b0cc 100644 --- a/arch/arm/boot/dts/omap4-droid4-xt894.dts +++ b/arch/arm/boot/dts/omap4-droid4-xt894.dts @@ -314,7 +314,7 @@ &mmc2 { vmmc-supply = <&vsdio>; bus-width = <8>; - non-removable; + ti,non-removable; }; &mmc3 { diff --git a/arch/arm/boot/dts/qcom-msm8974-lge-nexus5-hammerhead.dts b/arch/arm/boot/dts/qcom-msm8974-lge-nexus5-hammerhead.dts index 4dc0b347b1eed522e696ecb85b98f8a9f936ab74..c2dc9d09484abd41d43d13a7a70b0f986a926e19 100644 --- a/arch/arm/boot/dts/qcom-msm8974-lge-nexus5-hammerhead.dts +++ b/arch/arm/boot/dts/qcom-msm8974-lge-nexus5-hammerhead.dts @@ -189,6 +189,8 @@ regulator-max-microvolt = <2950000>; regulator-boot-on; + regulator-system-load = <200000>; + regulator-allow-set-load; }; l21 { diff --git a/arch/arm/boot/dts/tegra30-cardhu.dtsi b/arch/arm/boot/dts/tegra30-cardhu.dtsi index 92a9740c533f217a10cd6fb4421d2fc6871d015d..3b1db7b9ec502c444aedc438c89fda6777347ad6 100644 --- a/arch/arm/boot/dts/tegra30-cardhu.dtsi +++ b/arch/arm/boot/dts/tegra30-cardhu.dtsi @@ -206,6 +206,7 @@ #address-cells = <1>; #size-cells = <0>; reg = <0x70>; + reset-gpio = <&gpio TEGRA_GPIO(BB, 0) GPIO_ACTIVE_LOW>; }; }; diff --git a/arch/arm/configs/imx_v4_v5_defconfig b/arch/arm/configs/imx_v4_v5_defconfig index ca0f13cafe387e0a0009a8fd9ad97d87f8b2b62a..6e5a3d9c23e1027bd9a3c136b8610e9a641f6192 100644 --- a/arch/arm/configs/imx_v4_v5_defconfig +++ b/arch/arm/configs/imx_v4_v5_defconfig @@ -144,9 +144,11 @@ CONFIG_USB_STORAGE=y CONFIG_USB_CHIPIDEA=y CONFIG_USB_CHIPIDEA_UDC=y CONFIG_USB_CHIPIDEA_HOST=y +CONFIG_USB_CHIPIDEA_ULPI=y CONFIG_NOP_USB_XCEIV=y CONFIG_USB_GADGET=y CONFIG_USB_ETH=m +CONFIG_USB_ULPI_BUS=y CONFIG_MMC=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y diff --git a/arch/arm/configs/vendor/qcs405-perf_defconfig b/arch/arm/configs/vendor/qcs405-perf_defconfig index cac4e74b3625b4602033e92836f7279a781b9cf2..1d38035193c221a74a08e06aea551dcd0fe75a97 100644 --- a/arch/arm/configs/vendor/qcs405-perf_defconfig +++ b/arch/arm/configs/vendor/qcs405-perf_defconfig @@ -1,3 +1,4 @@ +CONFIG_POSIX_MQUEUE=y CONFIG_AUDIT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y @@ -241,6 +242,7 @@ CONFIG_PPP_SYNC_TTY=y CONFIG_USB_USBNET=y CONFIG_USB_NET_SMSC75XX=y CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_CLD_LL_CORE=y CONFIG_INPUT_EVDEV=y CONFIG_INPUT_EVBUG=m CONFIG_INPUT_KEYRESET=y @@ -419,6 +421,8 @@ CONFIG_MSM_SYSMON_QMI_COMM=y CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_BOOT_STATS=y CONFIG_QCOM_DCC_V2=y +CONFIG_ICNSS=y +CONFIG_ICNSS_QMI=y CONFIG_QCOM_BUS_SCALING=y CONFIG_MSM_TZ_SMMU=y CONFIG_QCOM_GLINK=y @@ -454,6 +458,7 @@ CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y CONFIG_PAGE_OWNER=y CONFIG_MAGIC_SYSRQ=y CONFIG_PANIC_ON_RECURSIVE_FAULT=y @@ -481,3 +486,4 @@ CONFIG_CRYPTO_CTR=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y +CONFIG_STACK_HASH_ORDER_SHIFT=12 diff --git a/arch/arm/configs/vendor/qcs405_defconfig b/arch/arm/configs/vendor/qcs405_defconfig index a1d99420a0b894c7b96fd571d551aa9b5c3044d9..97b15d085cf70e2ebbd8090874ac01afaea935eb 100644 --- a/arch/arm/configs/vendor/qcs405_defconfig +++ b/arch/arm/configs/vendor/qcs405_defconfig @@ -1,3 +1,4 @@ +CONFIG_POSIX_MQUEUE=y CONFIG_AUDIT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y @@ -252,6 +253,7 @@ CONFIG_PPP_SYNC_TTY=y CONFIG_USB_USBNET=y CONFIG_USB_NET_SMSC75XX=y CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_CLD_LL_CORE=y CONFIG_INPUT_EVDEV=y CONFIG_INPUT_EVBUG=m CONFIG_INPUT_KEYRESET=y @@ -444,6 +446,9 @@ CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_CORE_HANG_DETECT=y CONFIG_QCOM_DCC_V2=y +CONFIG_ICNSS=y +CONFIG_ICNSS_DEBUG=y +CONFIG_ICNSS_QMI=y CONFIG_QCOM_BUS_SCALING=y CONFIG_MSM_TZ_SMMU=y CONFIG_QCOM_GLINK=y diff --git a/arch/arm/configs/vendor/sdxprairie-perf_defconfig b/arch/arm/configs/vendor/sdxprairie-perf_defconfig index f05ed759f25df45315c7f771943b291032a6351d..d68246f942d2659bae7817d2f553e05491ea121b 100644 --- a/arch/arm/configs/vendor/sdxprairie-perf_defconfig +++ b/arch/arm/configs/vendor/sdxprairie-perf_defconfig @@ -140,6 +140,7 @@ CONFIG_BRIDGE=y CONFIG_NET_SCHED=y CONFIG_NET_SCH_PRIO=y CONFIG_QRTR=y +CONFIG_QRTR_SMD=y CONFIG_BT=y CONFIG_BT_RFCOMM=y CONFIG_BT_RFCOMM_TTY=y @@ -211,6 +212,7 @@ CONFIG_POWER_RESET=y CONFIG_POWER_SUPPLY=y CONFIG_THERMAL=y CONFIG_REGULATOR=y +CONFIG_REGULATOR_STUB=y CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_SOC=y @@ -271,20 +273,32 @@ CONFIG_RMNET_IPA3=y CONFIG_ECM_IPA=y CONFIG_RNDIS_IPA=y CONFIG_IPA_UT=y +CONFIG_MSM_CLK_AOP_QMP=y CONFIG_MSM_CLK_RPMH=y +CONFIG_GCC_SDXPRAIRIE=y +CONFIG_DEBUGCC_SDXPRAIRIE=y CONFIG_HWSPINLOCK=y CONFIG_HWSPINLOCK_QCOM=y +CONFIG_QCOM_APCS_IPC=y +CONFIG_MSM_QMP=y CONFIG_IOMMU_IO_PGTABLE_FAST=y CONFIG_ARM_SMMU=y CONFIG_IOMMU_DEBUG=y CONFIG_IOMMU_DEBUG_TRACKING=y CONFIG_IOMMU_TESTS=y +CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_QCOM_GLINK_SMEM=y CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y +CONFIG_QCOM_SMP2P=y CONFIG_QCOM_BUS_SCALING=y CONFIG_QCOM_BUS_CONFIG_RPMH=y CONFIG_QCOM_COMMAND_DB=y CONFIG_QTI_RPMH_API=y +CONFIG_QCOM_GLINK=y +CONFIG_QCOM_GLINK_PKT=y +CONFIG_QTI_RPM_STATS_LOG=y +CONFIG_MSM_PM=y CONFIG_PWM=y CONFIG_ANDROID=y CONFIG_EXT3_FS=y diff --git a/arch/arm/configs/vendor/sdxprairie_defconfig b/arch/arm/configs/vendor/sdxprairie_defconfig index 70638716e47b6afa3be37785f0e491802dd4215e..1cff52cdc91f11769d6212d2b62ec3bcb390293b 100644 --- a/arch/arm/configs/vendor/sdxprairie_defconfig +++ b/arch/arm/configs/vendor/sdxprairie_defconfig @@ -140,6 +140,7 @@ CONFIG_BRIDGE=y CONFIG_NET_SCHED=y CONFIG_NET_SCH_PRIO=y CONFIG_QRTR=y +CONFIG_QRTR_SMD=y CONFIG_CFG80211=y CONFIG_RFKILL=y CONFIG_DMA_CMA=y @@ -201,6 +202,7 @@ CONFIG_POWER_RESET=y CONFIG_POWER_SUPPLY=y CONFIG_THERMAL=y CONFIG_REGULATOR=y +CONFIG_REGULATOR_STUB=y CONFIG_FB=y CONFIG_SOUND=y CONFIG_SND=y @@ -261,21 +263,33 @@ CONFIG_RMNET_IPA3=y CONFIG_ECM_IPA=y CONFIG_RNDIS_IPA=y CONFIG_IPA_UT=y +CONFIG_MSM_CLK_AOP_QMP=y CONFIG_MSM_CLK_RPMH=y +CONFIG_GCC_SDXPRAIRIE=y +CONFIG_DEBUGCC_SDXPRAIRIE=y CONFIG_HWSPINLOCK=y CONFIG_HWSPINLOCK_QCOM=y +CONFIG_QCOM_APCS_IPC=y +CONFIG_MSM_QMP=y CONFIG_IOMMU_IO_PGTABLE_FAST=y CONFIG_ARM_SMMU=y CONFIG_IOMMU_DEBUG=y CONFIG_IOMMU_DEBUG_TRACKING=y CONFIG_IOMMU_TESTS=y +CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_QCOM_GLINK_SMEM=y CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_SMEM=y +CONFIG_QCOM_SMP2P=y CONFIG_MSM_BOOT_STATS=y CONFIG_QCOM_BUS_SCALING=y CONFIG_QCOM_BUS_CONFIG_RPMH=y CONFIG_QCOM_COMMAND_DB=y CONFIG_QTI_RPMH_API=y +CONFIG_QCOM_GLINK=y +CONFIG_QCOM_GLINK_PKT=y +CONFIG_QTI_RPM_STATS_LOG=y +CONFIG_MSM_PM=y CONFIG_PWM=y CONFIG_ANDROID=y CONFIG_STM=y diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index 25f12118c364839c7f8337852789a30c22655e8e..2f6ac1afa8046769e23f8118bad4babc22cc94ce 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -773,7 +773,7 @@ static struct gpiod_lookup_table mmc_gpios_table = { GPIO_LOOKUP("davinci_gpio.0", DA850_MMCSD_CD_PIN, "cd", GPIO_ACTIVE_LOW), GPIO_LOOKUP("davinci_gpio.0", DA850_MMCSD_WP_PIN, "wp", - GPIO_ACTIVE_LOW), + GPIO_ACTIVE_HIGH), }, }; diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c index b529ba04ed16656aeefc80eb5a4bb95119b6753d..eafa26d9f692d5a1ac654bc4167497d68c44dd3e 100644 --- a/arch/arm/mach-exynos/suspend.c +++ b/arch/arm/mach-exynos/suspend.c @@ -209,6 +209,7 @@ static int __init exynos_pmu_irq_init(struct device_node *node, NULL); if (!domain) { iounmap(pmu_base_addr); + pmu_base_addr = NULL; return -ENOMEM; } diff --git a/arch/arm/mach-hisi/hotplug.c b/arch/arm/mach-hisi/hotplug.c index a129aae7260286fcaf77bc110bce3dea71fb679e..909bb24937812028a706fe865de275b228d1f53d 100644 --- a/arch/arm/mach-hisi/hotplug.c +++ b/arch/arm/mach-hisi/hotplug.c @@ -148,13 +148,20 @@ static int hi3xxx_hotplug_init(void) struct device_node *node; node = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl"); - if (node) { - ctrl_base = of_iomap(node, 0); - id = HI3620_CTRL; - return 0; + if (!node) { + id = ERROR_CTRL; + return -ENOENT; } - id = ERROR_CTRL; - return -ENOENT; + + ctrl_base = of_iomap(node, 0); + of_node_put(node); + if (!ctrl_base) { + id = ERROR_CTRL; + return -ENOMEM; + } + + id = HI3620_CTRL; + return 0; } void hi3xxx_set_cpu(int cpu, bool enable) @@ -173,11 +180,15 @@ static bool hix5hd2_hotplug_init(void) struct device_node *np; np = of_find_compatible_node(NULL, NULL, "hisilicon,cpuctrl"); - if (np) { - ctrl_base = of_iomap(np, 0); - return true; - } - return false; + if (!np) + return false; + + ctrl_base = of_iomap(np, 0); + of_node_put(np); + if (!ctrl_base) + return false; + + return true; } void hix5hd2_set_cpu(int cpu, bool enable) @@ -219,10 +230,10 @@ void hip01_set_cpu(int cpu, bool enable) if (!ctrl_base) { np = of_find_compatible_node(NULL, NULL, "hisilicon,hip01-sysctrl"); - if (np) - ctrl_base = of_iomap(np, 0); - else - BUG(); + BUG_ON(!np); + ctrl_base = of_iomap(np, 0); + of_node_put(np); + BUG_ON(!ctrl_base); } if (enable) { diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 27a78c80e5b17352aafc4924d04694217bfa5c15..73d5d72dfc3e520894a85875de94791fac84236d 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -116,8 +116,8 @@ void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr) PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu)); } -extern unsigned char mvebu_boot_wa_start; -extern unsigned char mvebu_boot_wa_end; +extern unsigned char mvebu_boot_wa_start[]; +extern unsigned char mvebu_boot_wa_end[]; /* * This function sets up the boot address workaround needed for SMP @@ -130,7 +130,7 @@ int mvebu_setup_boot_addr_wa(unsigned int crypto_eng_target, phys_addr_t resume_addr_reg) { void __iomem *sram_virt_base; - u32 code_len = &mvebu_boot_wa_end - &mvebu_boot_wa_start; + u32 code_len = mvebu_boot_wa_end - mvebu_boot_wa_start; mvebu_mbus_del_window(BOOTROM_BASE, BOOTROM_SIZE); mvebu_mbus_add_window_by_id(crypto_eng_target, crypto_eng_attribute, diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c index 69df3620eca5ce1720f88ab86cf5a36df891d7e7..1c73694c871ad8289b572056d5c3727f3ee22eb2 100644 --- a/arch/arm/mach-omap2/omap-smp.c +++ b/arch/arm/mach-omap2/omap-smp.c @@ -109,6 +109,45 @@ void omap5_erratum_workaround_801819(void) static inline void omap5_erratum_workaround_801819(void) { } #endif +#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR +/* + * Configure ACR and enable ACTLR[0] (Enable invalidates of BTB with + * ICIALLU) to activate the workaround for secondary Core. + * NOTE: it is assumed that the primary core's configuration is done + * by the boot loader (kernel will detect a misconfiguration and complain + * if this is not done). + * + * In General Purpose(GP) devices, ACR bit settings can only be done + * by ROM code in "secure world" using the smc call and there is no + * option to update the "firmware" on such devices. This also works for + * High security(HS) devices, as a backup option in case the + * "update" is not done in the "security firmware". + */ +static void omap5_secondary_harden_predictor(void) +{ + u32 acr, acr_mask; + + asm volatile ("mrc p15, 0, %0, c1, c0, 1" : "=r" (acr)); + + /* + * ACTLR[0] (Enable invalidates of BTB with ICIALLU) + */ + acr_mask = BIT(0); + + /* Do we already have it done.. if yes, skip expensive smc */ + if ((acr & acr_mask) == acr_mask) + return; + + acr |= acr_mask; + omap_smc1(OMAP5_DRA7_MON_SET_ACR_INDEX, acr); + + pr_debug("%s: ARM ACR setup for CVE_2017_5715 applied on CPU%d\n", + __func__, smp_processor_id()); +} +#else +static inline void omap5_secondary_harden_predictor(void) { } +#endif + static void omap4_secondary_init(unsigned int cpu) { /* @@ -131,6 +170,8 @@ static void omap4_secondary_init(unsigned int cpu) set_cntfreq(); /* Configure ACR to disable streaming WA for 801819 */ omap5_erratum_workaround_801819(); + /* Enable ACR to allow for ICUALLU workaround */ + omap5_secondary_harden_predictor(); } /* diff --git a/arch/arm/mach-omap2/omap_hwmod_reset.c b/arch/arm/mach-omap2/omap_hwmod_reset.c index b68f9c0aff0b594d97af0c004c2525a7072197f0..d5ddba00bb7310bf0120902e2837dbddc4e90713 100644 --- a/arch/arm/mach-omap2/omap_hwmod_reset.c +++ b/arch/arm/mach-omap2/omap_hwmod_reset.c @@ -92,11 +92,13 @@ static void omap_rtc_wait_not_busy(struct omap_hwmod *oh) */ void omap_hwmod_rtc_unlock(struct omap_hwmod *oh) { - local_irq_disable(); + unsigned long flags; + + local_irq_save(flags); omap_rtc_wait_not_busy(oh); omap_hwmod_write(OMAP_RTC_KICK0_VALUE, oh, OMAP_RTC_KICK0_REG); omap_hwmod_write(OMAP_RTC_KICK1_VALUE, oh, OMAP_RTC_KICK1_REG); - local_irq_enable(); + local_irq_restore(flags); } /** @@ -110,9 +112,11 @@ void omap_hwmod_rtc_unlock(struct omap_hwmod *oh) */ void omap_hwmod_rtc_lock(struct omap_hwmod *oh) { - local_irq_disable(); + unsigned long flags; + + local_irq_save(flags); omap_rtc_wait_not_busy(oh); omap_hwmod_write(0x0, oh, OMAP_RTC_KICK0_REG); omap_hwmod_write(0x0, oh, OMAP_RTC_KICK1_REG); - local_irq_enable(); + local_irq_restore(flags); } diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c index 9c10248fadccc2d03ef3b3bcbddbe0b43347f158..4e8c2116808ecf3d36d36653184dc89d2941885e 100644 --- a/arch/arm/mach-pxa/irq.c +++ b/arch/arm/mach-pxa/irq.c @@ -185,7 +185,7 @@ static int pxa_irq_suspend(void) { int i; - for (i = 0; i < pxa_internal_irq_nr / 32; i++) { + for (i = 0; i < DIV_ROUND_UP(pxa_internal_irq_nr, 32); i++) { void __iomem *base = irq_base(i); saved_icmr[i] = __raw_readl(base + ICMR); @@ -204,7 +204,7 @@ static void pxa_irq_resume(void) { int i; - for (i = 0; i < pxa_internal_irq_nr / 32; i++) { + for (i = 0; i < DIV_ROUND_UP(pxa_internal_irq_nr, 32); i++) { void __iomem *base = irq_base(i); __raw_writel(saved_icmr[i], base + ICMR); diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig index a4065966881ae44d318ec4193d7091269541970c..57f0bc4cd9b89889c3b6f80b17f41f3b5eb0def8 100644 --- a/arch/arm/mach-rockchip/Kconfig +++ b/arch/arm/mach-rockchip/Kconfig @@ -18,6 +18,7 @@ config ARCH_ROCKCHIP select ARM_GLOBAL_TIMER select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK select ZONE_DMA if ARM_LPAE + select PM help Support for Rockchip's Cortex-A9 Single-to-Quad-Core-SoCs containing the RK2928, RK30xx and RK31xx series. diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 8902e2d3e217948f38f879589a6915ee4ecef6a9..236bc6ef269e0ab3cb78fda9924df78b89ea63a4 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -795,19 +795,28 @@ static int __mark_rodata_ro(void *unused) return 0; } +static int kernel_set_to_readonly __read_mostly; + void mark_rodata_ro(void) { + kernel_set_to_readonly = 1; stop_machine(__mark_rodata_ro, NULL, NULL); } void set_kernel_text_rw(void) { + if (!kernel_set_to_readonly) + return; + set_section_perms(ro_perms, ARRAY_SIZE(ro_perms), false, current->active_mm); } void set_kernel_text_ro(void) { + if (!kernel_set_to_readonly) + return; + set_section_perms(ro_perms, ARRAY_SIZE(ro_perms), true, current->active_mm); } diff --git a/arch/arm/probes/kprobes/core.c b/arch/arm/probes/kprobes/core.c index 52d1cd14fda45d961ece2d0c4d417d986a372de9..091e9a3c2dcb10d39ae877c2d586384b4ddc52fe 100644 --- a/arch/arm/probes/kprobes/core.c +++ b/arch/arm/probes/kprobes/core.c @@ -291,8 +291,8 @@ void __kprobes kprobe_handler(struct pt_regs *regs) break; case KPROBE_REENTER: /* A nested probe was hit in FIQ, it is a BUG */ - pr_warn("Unrecoverable kprobe detected at %p.\n", - p->addr); + pr_warn("Unrecoverable kprobe detected.\n"); + dump_kprobe(p); /* fall through */ default: /* impossible cases */ diff --git a/arch/arm/probes/kprobes/test-core.c b/arch/arm/probes/kprobes/test-core.c index 1c98a87786ca768adb622f1720df442a272bfb75..a10d7187ad2c51ecc07f6dc2334d7cd5482cb35a 100644 --- a/arch/arm/probes/kprobes/test-core.c +++ b/arch/arm/probes/kprobes/test-core.c @@ -1517,7 +1517,6 @@ static bool check_test_results(void) print_registers(&result_regs); if (mem) { - pr_err("current_stack=%p\n", current_stack); pr_err("expected_memory:\n"); print_memory(expected_memory, mem_size); pr_err("result_memory:\n"); diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index fe09621bfb33f4bb1144fb30c02e0e1e0fffd02e..cdc9eaf788b88bf3ab9a2f345dd43abefac6e1d6 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -742,7 +742,6 @@ config NEED_PER_CPU_EMBED_FIRST_CHUNK config HOLES_IN_ZONE def_bool y - depends on NUMA source kernel/Kconfig.preempt source kernel/Kconfig.hz diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index 1fd95d45199f5d1ab8c60fe2b90e49b6fc9b546b..3cf434661d3446d8b9e1aa777fa82163a269bacf 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -185,6 +185,14 @@ config ARCH_SDMMAGPIE This enables support for the SDMMAGPIE chipset. If you do not wish to build a kernel that runs on this chipset, say 'N' here. +config ARCH_TRINKET + bool "Enable Support for Qualcomm Technologies, Inc. TRINKET" + depends on ARCH_QCOM + select COMMON_CLK_QCOM + help + This enables support for the TRINKET chipset. If you do not + wish to build a kernel that runs on this chipset, say 'N' here. + config ARCH_REALTEK bool "Realtek Platforms" help @@ -197,6 +205,7 @@ config ARCH_ROCKCHIP select GPIOLIB select PINCTRL select PINCTRL_ROCKCHIP + select PM select ROCKCHIP_TIMER help This enables support for the ARMv8 based Rockchip chipsets, diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-mali.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl-mali.dtsi index f06cc234693b76511a27a33c140caf8c8a270c49..379abc3d82fe56836a2603a4e446eee3835895be 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxl-mali.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-mali.dtsi @@ -7,7 +7,7 @@ &apb { mali: gpu@c0000 { - compatible = "amlogic,meson-gxbb-mali", "arm,mali-450"; + compatible = "amlogic,meson-gxl-mali", "arm,mali-450"; reg = <0x0 0xc0000 0x0 0x40000>; interrupts = , , diff --git a/arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi b/arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi index 35c8457e3d1f23d32c3db46cbf43f95a3e1ef795..0b72094bcf5a2f63ba4e6229b8f67e1084814496 100644 --- a/arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi +++ b/arch/arm64/boot/dts/broadcom/northstar2/ns2.dtsi @@ -118,7 +118,7 @@ #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &gic 0 GIC_SPI 281 IRQ_TYPE_NONE>; + interrupt-map = <0 0 0 0 &gic 0 GIC_SPI 281 IRQ_TYPE_LEVEL_HIGH>; linux,pci-domain = <0>; @@ -149,7 +149,7 @@ #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0>; - interrupt-map = <0 0 0 0 &gic 0 GIC_SPI 305 IRQ_TYPE_NONE>; + interrupt-map = <0 0 0 0 &gic 0 GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>; linux,pci-domain = <4>; @@ -566,7 +566,7 @@ reg = <0x66080000 0x100>; #address-cells = <1>; #size-cells = <0>; - interrupts = ; + interrupts = ; clock-frequency = <100000>; status = "disabled"; }; @@ -594,7 +594,7 @@ reg = <0x660b0000 0x100>; #address-cells = <1>; #size-cells = <0>; - interrupts = ; + interrupts = ; clock-frequency = <100000>; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/broadcom/stingray/bcm958742k.dts b/arch/arm64/boot/dts/broadcom/stingray/bcm958742k.dts index eb6f08cdbd796c3d764393f9e2e70db2129b0e28..77efa28c4dd53db718b22e64569385f6d92c2feb 100644 --- a/arch/arm64/boot/dts/broadcom/stingray/bcm958742k.dts +++ b/arch/arm64/boot/dts/broadcom/stingray/bcm958742k.dts @@ -43,6 +43,10 @@ enet-phy-lane-swap; }; +&sdio0 { + mmc-ddr-1_8v; +}; + &uart2 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/broadcom/stingray/bcm958742t.dts b/arch/arm64/boot/dts/broadcom/stingray/bcm958742t.dts index 5084b037320fd9cb65133ca929517062a245af3b..55ba495ef56e1f54b518483bc9e5369fcb03b441 100644 --- a/arch/arm64/boot/dts/broadcom/stingray/bcm958742t.dts +++ b/arch/arm64/boot/dts/broadcom/stingray/bcm958742t.dts @@ -42,3 +42,7 @@ &gphy0 { enet-phy-lane-swap; }; + +&sdio0 { + mmc-ddr-1_8v; +}; diff --git a/arch/arm64/boot/dts/broadcom/stingray/stingray.dtsi b/arch/arm64/boot/dts/broadcom/stingray/stingray.dtsi index e6f75c633623cf45b9efc67844149551eb343e83..2b76293b51c838d79c03589ec40ce5cdc9479a42 100644 --- a/arch/arm64/boot/dts/broadcom/stingray/stingray.dtsi +++ b/arch/arm64/boot/dts/broadcom/stingray/stingray.dtsi @@ -409,7 +409,7 @@ reg = <0x000b0000 0x100>; #address-cells = <1>; #size-cells = <0>; - interrupts = ; + interrupts = ; clock-frequency = <100000>; status = "disabled"; }; @@ -453,7 +453,7 @@ reg = <0x000e0000 0x100>; #address-cells = <1>; #size-cells = <0>; - interrupts = ; + interrupts = ; clock-frequency = <100000>; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index ba1102b2c570d6d951102fd8ea37b1624c8a52eb..39a35cd5e85f36dfcae8216ee064ca5757f82392 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -32,11 +32,15 @@ ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) sm8150-qrd-overlay.dtbo \ sm8150-qrd-dvt-overlay.dtbo \ sa8155-adp-star-overlay.dtbo \ - sa8155p-adp-star-overlay.dtbo \ + sa8155p-adp-star-overlay.dtbo \ + sa8155-adp-air-overlay.dtbo \ + sa8155p-adp-air-overlay.dtbo \ sm8150-sdx50m-cdp-overlay.dtbo \ sm8150-sdx50m-mtp-overlay.dtbo \ sm8150-sdx50m-mtp-2.5k-panel-overlay.dtbo \ - sm8150-sdx50m-qrd-overlay.dtbo + sm8150-sdx50m-qrd-overlay.dtbo \ + sm8150-sdxprairie-cdp-overlay.dtbo \ + sm8150-sdxprairie-mtp-overlay.dtbo sm8150-cdp-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150p.dtb sm8150p-v2.dtb sm8150-mtp-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150p.dtb sm8150p-v2.dtb @@ -45,19 +49,25 @@ sm8150-qrd-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150p.dtb sm8150p-v2. sm8150-qrd-dvt-overlay.dtbo-base := sm8150-v2.dtb sm8150p-v2.dtb sa8155-adp-star-overlay.dtbo-base := sa8155.dtb sa8155-v2.dtb sa8155p-adp-star-overlay.dtbo-base := sa8155p.dtb sa8155p-v2.dtb +sa8155-adp-air-overlay.dtbo-base := sa8155.dtb sa8155-v2.dtb +sa8155p-adp-air-overlay.dtbo-base := sa8155p.dtb sa8155p-v2.dtb sm8150-sdx50m-cdp-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150p.dtb sm8150p-v2.dtb sm8150-sdx50m-mtp-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150p.dtb sm8150p-v2.dtb sm8150-sdx50m-mtp-2.5k-panel-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150p.dtb sm8150p-v2.dtb sm8150-sdx50m-qrd-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150p.dtb sm8150p-v2.dtb +sm8150-sdxprairie-cdp-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150p.dtb sm8150p-v2.dtb +sm8150-sdxprairie-mtp-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150p.dtb sm8150p-v2.dtb else dtb-$(CONFIG_ARCH_SM8150) += sm8150-rumi.dtb \ sm8150-mtp.dtb \ sm8150-cdp.dtb \ sm8150-qrd.dtb \ sa8155-adp-star.dtb \ - sa8155p-adp-star.dtb \ - sa8155-v2-adp-star.dtb \ - sa8155p-v2-adp-star.dtb \ + sa8155p-adp-star.dtb \ + sa8155-v2-adp-star.dtb \ + sa8155p-v2-adp-star.dtb \ + sa8155-v2-adp-air.dtb \ + sa8155p-v2-adp-air.dtb \ sm8150-v2-rumi.dtb \ sm8150-v2-mtp.dtb \ sm8150-v2-cdp.dtb \ @@ -93,6 +103,7 @@ ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) sm6150p-idp-overlay.dtbo \ sm6150-external-codec-idp-overlay.dtbo \ sm6150-usbc-idp-overlay.dtbo \ + sm6150-usbc-minidp-idp-overlay.dtbo \ sm6150-cmd-mode-display-idp-overlay.dtbo \ sa6155-adp-star-overlay.dtbo \ sa6155p-adp-star-overlay.dtbo @@ -104,6 +115,7 @@ sm6150p-qrd-overlay.dtbo-base := sm6150p.dtb sm6150p-idp-overlay.dtbo-base := sm6150p.dtb sm6150-external-codec-idp-overlay.dtbo-base := sm6150.dtb sm6150-usbc-idp-overlay.dtbo-base := sm6150.dtb +sm6150-usbc-minidp-idp-overlay.dtbo-base := sm6150.dtb sm6150-cmd-mode-display-idp-overlay.dtbo-base := sm6150.dtb sa6155-adp-star-overlay.dtbo-base := sa6155.dtb sa6155p-adp-star-overlay.dtbo-base := sa6155p.dtb @@ -115,6 +127,7 @@ dtb-$(CONFIG_ARCH_SM6150) += sm6150-rumi.dtb \ sm6150p-idp.dtb \ sm6150-external-codec-idp.dtb \ sm6150-usbc-idp.dtb \ + sm6150-usbc-minidp-idp.dtb \ sm6150-cmd-mode-display-idp.dtb \ sa6155-adp-star.dtb \ sa6155p-adp-star.dtb @@ -127,19 +140,34 @@ ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) sdmmagpie-rumi-overlay.dtbo \ sdmmagpie-qrd-overlay.dtbo \ sdmmagpiep-idp-overlay.dtbo \ - sdmmagpiep-qrd-overlay.dtbo + sdmmagpiep-qrd-overlay.dtbo \ + sdmmagpie-external-codec-idp-overlay.dtbo \ + sdmmagpie-usbc-idp-overlay.dtbo sdmmagpie-idp-overlay.dtbo-base := sdmmagpie.dtb sdmmagpie-rumi-overlay.dtbo-base := sdmmagpie.dtb sdmmagpie-qrd-overlay.dtbo-base := sdmmagpie.dtb sdmmagpiep-idp-overlay.dtbo-base := sdmmagpiep.dtb sdmmagpiep-qrd-overlay.dtbo-base := sdmmagpiep.dtb +sdmmagpie-external-codec-idp-overlay.dtbo-base := sdmmagpie.dtb +sdmmagpie-usbc-idp-overlay.dtbo-base := sdmmagpie.dtb else dtb-$(CONFIG_ARCH_SDMMAGPIE) += sdmmagpie-rumi.dtb \ sdmmagpie-idp.dtb \ sdmmagpie-qrd.dtb \ sdmmagpiep-idp.dtb \ - sdmmagpiep-qrd.dtb + sdmmagpiep-qrd.dtb \ + sdmmagpie-external-codec-idp.dtb \ + sdmmagpie-usbc-idp.dtb +endif + +ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) + dtbo-$(CONFIG_ARCH_TRINKET) += \ + trinket-rumi-overlay.dtbo + +trinket-rumi-overlay.dtbo-base := trinket.dtb +else +dtb-$(CONFIG_ARCH_TRINKET) += trinket-rumi.dtb endif dtb-$(CONFIG_ARCH_SDXPRAIRIE) += sdxprairie-rumi.dtb \ diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi b/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi index 1d63e6b879de7cc51784077be9b138f9f5635c8e..b6b44fdf7face8b00690bede37d09d59debed242 100644 --- a/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi +++ b/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi @@ -187,7 +187,7 @@ led@6 { label = "apq8016-sbc:blue:bt"; gpios = <&pm8916_mpps 3 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "bt"; + linux,default-trigger = "bluetooth-power"; default-state = "off"; }; }; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi index ac8a95632b72787a86d7cfa15e490a832eb9322b..50adcde6e5969a595426e3201d33d0c05c8e12de 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -37,6 +37,7 @@ qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; qcom,mdss-pan-physical-width-dimension = <74>; qcom,mdss-pan-physical-height-dimension = <131>; + qcom,mdss-dsi-dma-schedule-line = <5>; qcom,mdss-dsi-display-timings { timing@0{ diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sw43404-amoled-dsc-fhd-plus-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sw43404-amoled-dsc-fhd-plus-cmd.dtsi index d97a61ed568e2a887f08df21d26c179caf19a614..b72af1196ddbbb4683dd8301b91aa31bae530106 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-sw43404-amoled-dsc-fhd-plus-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sw43404-amoled-dsc-fhd-plus-cmd.dtsi @@ -99,7 +99,7 @@ qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; qcom,compression-mode = "dsc"; - qcom,mdss-dsc-slice-height = <540>; + qcom,mdss-dsc-slice-height = <270>; qcom,mdss-dsc-slice-width = <540>; qcom,mdss-dsc-slice-per-pkt = <1>; qcom,mdss-dsc-bit-per-component = <8>; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sw43404-amoled-dsc-wqhd-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sw43404-amoled-dsc-wqhd-cmd.dtsi index cd1993d9669ed22263232cfa73ce169cad0fd787..123ba34e60dcd2af668593e1f308b5e135fe349d 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-sw43404-amoled-dsc-wqhd-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sw43404-amoled-dsc-wqhd-cmd.dtsi @@ -86,6 +86,9 @@ 15 01 00 00 00 00 02 55 0c 05 01 00 00 1e 00 02 11 00 39 01 00 00 00 00 03 b0 a5 00 + 15 01 00 00 00 00 02 e0 18 + 39 01 00 00 00 00 0c c0 00 53 6f 51 50 + 51 34 4f 5a 33 19 05 01 00 00 78 00 02 35 00 05 01 00 00 3c 00 02 29 00 ]; @@ -104,8 +107,18 @@ [15 01 00 00 00 00 02 5a 00]; qcom,mdss-dsi-qsync-off-commands-state = "dsi_lp_mode"; + qcom,mdss-dsi-lp1-command = [ + 05 01 00 00 00 00 02 39 00 + ]; + qcom,mdss-dsi-lp1-command-state = + "dsi_lp_mode"; + qcom,mdss-dsi-nolp-command = [ + 05 01 00 00 00 00 02 38 00 + ]; + qcom,mdss-dsi-nolp-command-state = + "dsi_lp_mode"; qcom,compression-mode = "dsc"; - qcom,mdss-dsc-slice-height = <1440>; + qcom,mdss-dsc-slice-height = <180>; qcom,mdss-dsc-slice-width = <720>; qcom,mdss-dsc-slice-per-pkt = <1>; qcom,mdss-dsc-bit-per-component = <8>; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sw43404-amoled-dsc-wqhd-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sw43404-amoled-dsc-wqhd-video.dtsi index 97d5c6b1e5d70c9c9db327b6f0e6e4418a9877da..74ff912cab9411ead4bc0c46203cf742aeaabd3c 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-sw43404-amoled-dsc-wqhd-video.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sw43404-amoled-dsc-wqhd-video.dtsi @@ -50,8 +50,8 @@ qcom,mdss-dsi-h-left-border = <0>; qcom,mdss-dsi-panel-framerate = <60>; qcom,mdss-dsi-on-command = [ - 07 01 00 00 00 00 02 01 00 39 01 00 00 00 00 03 b0 a5 00 + 07 01 00 00 00 00 02 01 00 39 01 00 00 00 00 06 b2 00 5d 04 80 49 15 01 00 00 00 00 02 3d 10 15 01 00 00 00 00 02 36 00 @@ -62,6 +62,7 @@ 05 01 00 00 50 00 02 11 00 39 01 00 00 00 00 03 b0 34 04 39 01 00 00 00 00 05 c1 00 00 00 46 + 39 01 00 00 00 00 03 b0 a5 00 0a 01 00 00 00 00 80 11 00 00 89 30 80 0B 40 05 A0 02 d0 02 D0 02 D0 02 00 02 68 00 20 4e a8 00 0A 00 0C 00 23 diff --git a/arch/arm64/boot/dts/qcom/fg-gen4-batterydata-alium-3600mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen4-batterydata-alium-3600mah.dtsi index ad2d10c86459839dc80136d86c3f35c12a550ce8..595eba0b1d4cae1321a666a0922634e1151d9430 100644 --- a/arch/arm64/boot/dts/qcom/fg-gen4-batterydata-alium-3600mah.dtsi +++ b/arch/arm64/boot/dts/qcom/fg-gen4-batterydata-alium-3600mah.dtsi @@ -21,9 +21,10 @@ qcom,alium_860_89032_0000_3600mah_averaged_masterslave_sep24th2018 { qcom,jeita-fv-ranges = <0 100 4250000 110 400 4350000 410 450 4250000>; - qcom,step-chg-ranges = <3600000 4200000 5400000 - 4201000 4300000 3600000 + qcom,step-chg-ranges = <3600000 3800000 5400000 + 3801000 4300000 3600000 4301000 4350000 2500000>; + qcom,ocv-based-step-chg; qcom,batt-id-kohm = <107>; qcom,battery-beta = <4250>; qcom,therm-room-temp = <100000>; diff --git a/arch/arm64/boot/dts/qcom/fg-gen4-batterydata-mlp466076-3250mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen4-batterydata-mlp466076-3250mah.dtsi index ab69f4e034f666688d690a9b8755d8faaf1296c7..552c888d1510fe7b951f6c15c41a3516b261265f 100644 --- a/arch/arm64/boot/dts/qcom/fg-gen4-batterydata-mlp466076-3250mah.dtsi +++ b/arch/arm64/boot/dts/qcom/fg-gen4-batterydata-mlp466076-3250mah.dtsi @@ -11,8 +11,8 @@ * GNU General Public License for more details. */ -qcom,mlp466076_3250mah_averaged_masterslave_mar27th2018 { - /* #mlp466076_3250mAh_averaged_MasterSlave_Mar27th2018 */ +qcom,mlp466076_3250mah_averaged_masterslave_sept24th2018 { + /* #mlp466076_3250mAh_averaged_MasterSlave_sept24th2018 */ qcom,max-voltage-uv = <4400000>; qcom,fastchg-current-ma = <6000>; /* COLD = 0 DegC, HOT = 55 DegC */ @@ -29,115 +29,117 @@ qcom,mlp466076_3250mah_averaged_masterslave_mar27th2018 { qcom,battery-beta = <4250>; qcom,therm-room-temp = <100000>; qcom,fg-cc-cv-threshold-mv = <4390>; - qcom,battery-type = "mlp466076_3250mah_mar27th2018"; + qcom,battery-type = "qrd855_mlp466076_3200mah_sept24th2018"; qcom,therm-coefficients = <0x2318 0xd0c 0xdaf7 0xc556 0x848d>; qcom,therm-center-offset = <0x70>; - qcom,checksum = <0xC5FF>; - qcom,gui-version = "PM8150GUI - 0.0.0.32"; + qcom,rslow-normal-coeffs = <0x43 0xfc 0xc9 0x12>; + qcom,rslow-low-coeffs = <0x07 0x15 0x8d 0xf5>; + qcom,checksum = <0x7F72>; + qcom,gui-version = "PM8150GUI - 1.0.0.10"; qcom,fg-profile-data = [ - 09 00 31 EA - 85 C4 5A BA - 33 AA 00 00 - EE BC 66 8B - F6 87 AC 95 - 78 9A D2 87 - 2F 00 6C 0C - EF 02 B0 04 - 41 02 CE 07 - 00 00 A6 00 - 70 07 CD 06 - 64 14 66 25 - 55 1C 06 0A - E8 3A C0 43 - 40 00 37 00 - 40 00 4D 00 - 41 00 33 00 - 38 00 3B 00 - 43 00 4C 00 - 40 00 40 00 - 3E 00 3B 00 - 34 00 32 00 - 2F 00 56 00 - 4A 64 42 00 - 49 00 40 08 - 40 00 36 00 - 36 00 40 10 - 3C 10 36 00 - 64 28 4A 48 - 3E 60 39 0C - 40 00 D8 00 - 66 20 C1 0C - C7 02 61 FE - 2A 1C EA 0B - 5A 0D A2 22 - F6 17 3A 42 - 2E 55 7F 02 - 71 13 47 20 - B9 04 2E 0B - 9E 05 D4 1C - D5 03 F7 05 - 4D 02 8C 18 - D4 22 B5 45 - 90 52 7F 14 - AE 20 60 04 - 68 CB 66 AD - DC 1C 7C D1 - B1 05 D3 BA - 78 18 AA 8A - FD 85 18 92 - 8F A0 09 80 - 43 00 82 FC - 33 03 25 02 - 00 F8 FE EC - F4 DB F1 F7 - 68 0B EA 14 - 71 20 20 18 - A6 1E BD 03 - C8 05 54 01 + 09 00 53 00 + 77 DD 12 E2 + E4 DD 00 00 + 49 BC 7B 8B + F9 87 5A 9A + A8 86 C3 87 + 29 00 43 FC + C9 12 DC 04 + 75 FB CE 07 + 32 00 43 EB + 7A ED B9 B5 + EF 0A C4 E2 + 2B BC EF 0B + 40 02 5C DB + 60 00 46 00 + 49 00 48 00 + 3B 00 30 00 + 30 00 37 00 + 41 00 43 00 + 45 00 60 00 + 40 00 3A 00 + 36 00 36 00 + 33 00 5B 00 + 4F 64 4A 00 + 4F 08 4F 08 + 60 F8 4D 00 + 4A 00 5A 08 + 59 08 4E 00 + 93 20 6A 40 + 59 58 52 10 + 59 00 D8 08 + 6A 21 E7 0D + 42 03 1F FC + 5B 1C 1C 03 + 3A 04 8B 23 + FB 17 7A 3B + B1 4C 31 02 + 85 15 3A 21 + DB 0D E5 0B + F7 04 E0 1C + 4D FB F6 04 + 8B 03 7E 18 + 9C 22 29 3C + E3 4B 8C 16 + F6 20 FE ED + C5 D3 01 D5 + D5 1C 03 CB + AF 05 DD BA + 60 18 87 92 + 73 84 70 9B + 8F 98 09 80 + 67 FA 62 05 + 58 03 C9 04 + 00 00 1A E4 + C1 02 E9 0F + E0 EB 80 A2 + 6C 1F 1C 10 + 93 04 29 02 + 8D 04 6F 02 CE 07 32 00 - 15 03 4D 02 - 90 02 35 04 - 01 03 1D 03 - 47 03 DB 02 - 52 05 40 00 - 3B 00 3E 00 - 3F 64 40 00 - 41 00 3E 08 - 43 F8 40 00 - 40 08 40 10 - 40 10 36 00 - 3F 28 42 48 - 42 60 47 0C - 38 00 39 00 - 3F 08 40 00 - 40 00 40 00 - 2F 10 3D 10 - 3B 00 42 20 - 53 40 37 58 - 3D 0E 41 00 - 40 00 40 08 - D8 00 28 20 - 94 05 44 0A - 23 0D 8F 1C - 08 22 3D 45 - C4 52 4F 18 - 41 02 26 05 - 86 02 6A 11 - 3F 0A EA 1F - 59 05 BC 02 - FA 05 A2 1C - 77 03 92 05 - A5 02 84 18 - A0 03 34 04 - C6 02 67 00 - E9 1F 2B 05 - FE 02 A8 05 - C4 1C 83 02 - F1 04 66 03 - A6 18 FC 02 - 65 05 28 03 - 71 00 61 01 + C3 01 CA 02 + 6F 07 4A 03 + 03 05 EC 04 + 3E 04 71 04 + CD 02 4A 00 + 3D 00 40 00 + 42 64 44 00 + 43 00 47 08 + 44 00 4B 00 + 50 00 4F 10 + 46 10 3C 00 + 45 20 48 40 + 48 58 4D 0E + 48 00 40 00 + 46 08 5E 00 + 61 00 48 00 + 43 08 59 08 + 5B 00 5F 20 + 74 40 5F 50 + 53 10 5B 00 + 70 00 E6 08 + D8 00 DD 20 + 9A 04 2B 0B + 97 0D C7 1C + 55 23 E3 45 + 1B 52 89 18 + B9 03 18 04 + DB 02 74 12 + 3F 0A D4 20 + 4A 04 8A 03 + 32 05 C8 1C + DF 02 66 04 + C4 03 A7 18 + 2F 03 10 05 + C6 03 76 00 + D0 20 31 04 + AA 03 0E 05 + D3 1C 33 02 + A2 05 91 02 + AB 18 D6 02 + A7 05 B2 02 + 7F 00 7F 01 C0 00 FA 00 - 38 0D 00 00 + F2 0C 00 00 ]; }; diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150-v2.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150-v2.dtsi index c30e790780acb40a1347e76ca419cc97b3adbe47..737111fc0eba16d0ec82809e18fb7fae74872762 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sm8150-v2.dtsi @@ -70,7 +70,6 @@ #iommu-cells = <2>; qcom,skip-init; qcom,use-3-lvl-tables; - qcom,disable-atos; #global-interrupts = <1>; #size-cells = <1>; #address-cells = <1>; diff --git a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi index 08ea46eb3b49f63cfa22a53324c9c19351a6c4a4..bcd6a2383927884f325f5fee3628617f0accbb57 100644 --- a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi @@ -343,6 +343,16 @@ qcom,msm-dai-q6-dev-id = <16401>; }; + sb_9_rx: qcom,msm-dai-q6-sb-9-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16402>; + }; + + sb_9_tx: qcom,msm-dai-q6-sb-9-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16403>; + }; + bt_sco_rx: qcom,msm-dai-q6-bt-sco-rx { compatible = "qcom,msm-dai-q6-dev"; qcom,msm-dai-q6-dev-id = <12288>; diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi index 61da6e65900b2414c09a8d257f891772556f3e8e..3cc449425a0388530a9e755808cbe6dddee38f89 100644 --- a/arch/arm64/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi @@ -1132,14 +1132,14 @@ port@0 { reg = <0>; - etf_out: endpoint { + etf_in: endpoint { slave-mode; remote-endpoint = <&funnel0_out>; }; }; port@1 { reg = <0>; - etf_in: endpoint { + etf_out: endpoint { remote-endpoint = <&replicator_in>; }; }; diff --git a/arch/arm64/boot/dts/qcom/pm6150l.dtsi b/arch/arm64/boot/dts/qcom/pm6150l.dtsi index ae731febad45744155f4a56d87f060640ae969f5..6387c5624362edbdf66d041ff4b19c101f63d43d 100644 --- a/arch/arm64/boot/dts/qcom/pm6150l.dtsi +++ b/arch/arm64/boot/dts/qcom/pm6150l.dtsi @@ -151,6 +151,7 @@ interrupts = <0x5 0xec 0x1 IRQ_TYPE_EDGE_RISING>; interrupt-names = "sc-irq"; qcom,pmic-revid = <&pm6150l_revid>; + qcom,voltage-step-ramp; status = "disabled"; lcdb_ldo_vreg: ldo { @@ -299,11 +300,30 @@ reg = <0xd800 0x100>, <0xd900 0x100>; reg-names = "wled-ctrl-base", "wled-sink-base"; label = "backlight"; - interrupts = <0x5 0xd8 0x1 IRQ_TYPE_EDGE_RISING>; - interrupt-names = "ovp-irq"; + interrupts = <0x5 0xd8 0x1 IRQ_TYPE_EDGE_RISING>, + <0x5 0xd8 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x5 0xd8 0x5 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "ovp-irq", "pre-flash-irq", + "flash-irq"; qcom,pmic-revid = <&pm6150l_revid>; qcom,auto-calibration; status = "disabled"; + + wled_flash: qcom,wled-flash { + label = "flash"; + qcom,default-led-trigger = "wled_flash"; + }; + + wled_torch: qcom,wled-torch { + label = "torch"; + qcom,default-led-trigger = "wled_torch"; + qcom,wled-torch-timer = <1200>; + }; + + wled_switch: qcom,wled-switch { + label = "switch"; + qcom,default-led-trigger = "wled_switch"; + }; }; pm6150l_lpg: qcom,pwms@b100 { diff --git a/arch/arm64/boot/dts/qcom/pm8150b.dtsi b/arch/arm64/boot/dts/qcom/pm8150b.dtsi index 36ba994643f825f5d2b9db0864a6602db17ac0e6..da3e485049305151b392f6b31e6f9868ef3ea065 100644 --- a/arch/arm64/boot/dts/qcom/pm8150b.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8150b.dtsi @@ -53,7 +53,7 @@ pm8150b_qnovo: qcom,sdam-qnovo@b000 { compatible = "qcom,qpnp-qnovo5"; reg = <0xb000 0x100>; - interrupts = <0x2 0xb0 0 IRQ_TYPE_EDGE_RISING>; + interrupts = <0x2 0xb0 1 IRQ_TYPE_EDGE_RISING>; interrupt-names = "ptrain-done"; }; diff --git a/arch/arm64/boot/dts/qcom/pm8150l.dtsi b/arch/arm64/boot/dts/qcom/pm8150l.dtsi index c05ed990e278df4343fed2fffb5d585b2d603d1f..3c4e7d1a70314cf242c87cb20b9ee7cc93cf7205 100644 --- a/arch/arm64/boot/dts/qcom/pm8150l.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8150l.dtsi @@ -146,6 +146,7 @@ interrupts = <0x5 0xec 0x1 IRQ_TYPE_EDGE_RISING>; interrupt-names = "sc-irq"; qcom,pmic-revid = <&pm8150l_revid>; + qcom,voltage-step-ramp; status = "disabled"; lcdb_ldo_vreg: ldo { diff --git a/arch/arm64/boot/dts/qcom/qcs403-iot-sku1.dts b/arch/arm64/boot/dts/qcom/qcs403-iot-sku1.dts index a9ad2c5e99211c5f197bd74df618e1d530f495a7..b0c067b85a79232cab4e99c28b09f3c2536185ae 100644 --- a/arch/arm64/boot/dts/qcom/qcs403-iot-sku1.dts +++ b/arch/arm64/boot/dts/qcom/qcs403-iot-sku1.dts @@ -15,6 +15,7 @@ #include "qcs403.dtsi" #include "qcs405-audio-overlay.dtsi" +#include "qcs405-circular-pca9956.dtsi" / { model = "Qualcomm Technologies, Inc. QCS403 EVB2 1000 IOT"; diff --git a/arch/arm64/boot/dts/qcom/qcs403-iot-sku3.dts b/arch/arm64/boot/dts/qcom/qcs403-iot-sku3.dts index 852276034c230977694cf33b617b7f5daa5af3d5..9c2d52ac7b965c9feaf9c50085dd6d595a47fc94 100644 --- a/arch/arm64/boot/dts/qcom/qcs403-iot-sku3.dts +++ b/arch/arm64/boot/dts/qcom/qcs403-iot-sku3.dts @@ -14,7 +14,7 @@ /dts-v1/; #include "qcs403.dtsi" -#include "qcs405-audio-overlay.dtsi" +#include "qcs405-wsa-audio-overlay.dtsi" / { model = "Qualcomm Technologies, Inc. QCS403 SSRD IOT"; compatible = "qcom,qcs403-iot", "qcom,qcs403", "qcom,iot"; @@ -76,3 +76,7 @@ /delete-node/ cpuss-2-step; /delete-node/ cpuss-3-step; }; + +&qnand_1 { + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs405-audio.dtsi b/arch/arm64/boot/dts/qcom/qcs405-audio.dtsi index 69683700a14e351777911a717476080c0cc56498..1f31215e4e65695abdb2761f333e5d9b50138a3a 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-audio.dtsi @@ -103,7 +103,8 @@ <&wsa_cdc_dma_2_tx>, <&va_cdc_dma_0_tx>, <&va_cdc_dma_1_tx>, <&dai_pri_spdif_rx>, <&dai_pri_spdif_tx>, - <&dai_sec_spdif_rx>, <&dai_sec_spdif_tx>; + <&dai_sec_spdif_rx>, <&dai_sec_spdif_tx>, + <&sb_9_tx>; asoc-cpu-names = "msm-dai-q6-dp.24608", "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", @@ -138,7 +139,8 @@ "msm-dai-cdc-dma-dev.45089", "msm-dai-cdc-dma-dev.45091", "msm-dai-q6-spdif.20480", "msm-dai-q6-spdif.20481", - "msm-dai-q6-spdif.20482", "msm-dai-q6-spdif.20483"; + "msm-dai-q6-spdif.20482", "msm-dai-q6-spdif.20483", + "msm-dai-q6-dev.16403"; }; }; diff --git a/arch/arm64/boot/dts/qcom/qcs405-led-pca9956.dtsi b/arch/arm64/boot/dts/qcom/qcs405-circular-pca9956.dtsi similarity index 99% rename from arch/arm64/boot/dts/qcom/qcs405-led-pca9956.dtsi rename to arch/arm64/boot/dts/qcom/qcs405-circular-pca9956.dtsi index 332e805923a926c9595f4c228d9a73aa41568654..f7da0448d99c87d60db5c029e4c21b85f70a9402 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-led-pca9956.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-circular-pca9956.dtsi @@ -244,4 +244,3 @@ }; }; }; - diff --git a/arch/arm64/boot/dts/qcom/qcs405-coresight.dtsi b/arch/arm64/boot/dts/qcom/qcs405-coresight.dtsi index b31eeda371c4599cc66b4e745d954ea339d551bf..f13953d1ad29fe363d9339072f4509d3529ad571 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-coresight.dtsi @@ -934,7 +934,7 @@ compatible = "qcom,coresight-remote-etm"; coresight-name = "coresight-modem-etm0"; - qcom,inst-id = <3>; + qcom,inst-id = <2>; port{ modem_etm0_out_funnel_in2: endpoint { diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku1.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku1.dts index 0a60f153abcd6239e28b697f35e2bcf9c0709baa..672f903c453e6d0c86217f11fd6505f9d50ae3d3 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku1.dts +++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku1.dts @@ -15,6 +15,7 @@ #include "qcs405.dtsi" #include "qcs405-wsa-audio-overlay.dtsi" +#include "qcs405-circular-pca9956.dtsi" / { model = "Qualcomm Technologies, Inc. QCS405 EVB1 1000 IOT"; @@ -34,3 +35,35 @@ extcon = <&smb1351_otg_supply>; vbus_dwc3-supply = <&smb1351_otg_supply>; }; + +&soc { + gpio_keys { + vol_mute { + gpios = <&tlmm 19 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&tlmm { + evb_tlmm_gpio_key{ + tlmm_gpio_key_active: tlmm_gpio_key_active { + mux { + pins = "gpio19","gpio52","gpio54","gpio115"; + }; + + config { + pins = "gpio19","gpio52","gpio54","gpio115"; + }; + }; + + tlmm_gpio_key_suspend: tlmm_gpio_key_suspend { + mux { + pins = "gpio19","gpio52","gpio54","gpio115"; + }; + + config { + pins = "gpio19","gpio52","gpio54","gpio115"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku2.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku2.dts index 8f22d4c3b334a594f8ebaa641387fa87bc2cb3c5..07f309571b3ceb28ca2b16b3a2582c2ca9da5128 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku2.dts +++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku2.dts @@ -16,6 +16,7 @@ #include "qcs405.dtsi" #include "qcs405-audio-overlay.dtsi" #include "qcs405-geni-ir-overlay.dtsi" +#include "qcs405-circular-pca9956.dtsi" / { model = "Qualcomm Technologies, Inc. QCS405 EVB1 4000 SPI IOT"; diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku3.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku3.dts index 9ec18758df4dd289c25e4bad9b9310330a275716..a1814a55bcb32f8cd1193f564d01c211be9b7769 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku3.dts +++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku3.dts @@ -17,6 +17,7 @@ #include "qcs405-audio-overlay.dtsi" #include "qcs405-geni-ir-overlay.dtsi" #include "qcs405-pinctrl.dtsi" +#include "qcs405-circular-pca9956.dtsi" / { model = "Qualcomm Technologies, Inc. QCS405 sEVB/SLT IOT"; diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku4.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku4.dts index bbfce94ca0d88eb357268c2ee9aa7dbd342bad22..b266d4a64db6288d231212137b04dbf40f7c2ab0 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku4.dts +++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku4.dts @@ -16,6 +16,7 @@ #include "qcs405.dtsi" #include "qcs405-audio-overlay.dtsi" #include "qcs405-geni-ir-overlay.dtsi" +#include "qcs405-circular-pca9956.dtsi" / { model = "Qualcomm Technologies, Inc. QCS405 EVB1 4000 DSI IOT"; @@ -25,6 +26,21 @@ #include "qcs405-mdss-panels.dtsi" +&mdss_hdmi_tx { + pinctrl-names = "hdmi_hpd_active", "hdmi_ddc_active", "hdmi_cec_active", + "hdmi_active", "hdmi_sleep"; + pinctrl-0 = <&mdss_hdmi_5v_active &mdss_hdmi_hpd_active + &mdss_hdmi_ddc_suspend &mdss_hdmi_cec_suspend>; + pinctrl-1 = <&mdss_hdmi_5v_active &mdss_hdmi_hpd_active + &mdss_hdmi_ddc_active &mdss_hdmi_cec_suspend>; + pinctrl-2 = <&mdss_hdmi_5v_active &mdss_hdmi_hpd_active + &mdss_hdmi_cec_active &mdss_hdmi_ddc_suspend>; + pinctrl-3 = <&mdss_hdmi_5v_active &mdss_hdmi_hpd_active + &mdss_hdmi_ddc_active &mdss_hdmi_cec_active>; + pinctrl-4 = <&mdss_hdmi_5v_suspend &mdss_hdmi_hpd_suspend + &mdss_hdmi_ddc_suspend &mdss_hdmi_cec_suspend>; +}; + &mdss_mdp { qcom,mdss-pref-prim-intf = "dsi"; }; @@ -56,3 +72,14 @@ status = "ok"; }; }; + +&soc { + spi@78b5000 { + status = "ok"; + spi@0 { + compatible = "qcom,spi-msm-codec-slave"; + reg = <0>; + spi-max-frequency = <50000000>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku5.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku5.dts index 695e0500101dd6e7e8c92bf1d1833880eda290b6..433728cb4d54ff83ac565696b35fd89572fa2de5 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku5.dts +++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku5.dts @@ -16,6 +16,7 @@ #include "qcs405.dtsi" #include "qcs405-audio-overlay.dtsi" #include "qcs405-geni-ir-overlay.dtsi" +#include "qcs405-circular-pca9956.dtsi" / { model = "Qualcomm Technologies, Inc. QCS405 EVB1 4000 RGB IOT"; diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku6.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku6.dts index edd9d4d86dd0aa7a8f678ffeaa952685c23d61ba..6b5bb84799cddf1bb725a66c164b2b3a3684b173 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku6.dts +++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku6.dts @@ -16,6 +16,7 @@ #include "qcs405.dtsi" #include "qcs405-csra1-audio-overlay.dtsi" #include "qcs405-geni-ir-overlay.dtsi" +#include "qcs405-circular-pca9956.dtsi" / { model = "Qualcomm Technologies, Inc. QCS405 EVB1 4000 CSRA1 IOT"; diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku7.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku7.dts index ceac14d652d365a7bd5e653cd897b4dfc3eb56f5..02b537d433c3e112830aa9344d0cd22d90dd4b52 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku7.dts +++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku7.dts @@ -16,6 +16,7 @@ #include "qcs405.dtsi" #include "qcs405-csra6-audio-overlay.dtsi" #include "qcs405-geni-ir-overlay.dtsi" +#include "qcs405-linear-pca9956.dtsi" / { model = "Qualcomm Technologies, Inc. QCS405 EVB1 4000 CSRA6 IOT"; diff --git a/arch/arm64/boot/dts/qcom/qcs405-iot-sku8.dts b/arch/arm64/boot/dts/qcom/qcs405-iot-sku8.dts index ef26d1ae76d7fb7bd18a9eacdbfde15aaa509924..f08512ea1c58033d0b40bd3c6806227ed0a20740 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-iot-sku8.dts +++ b/arch/arm64/boot/dts/qcom/qcs405-iot-sku8.dts @@ -16,6 +16,7 @@ #include "qcs405.dtsi" #include "qcs405-amic-audio-overlay.dtsi" #include "qcs405-geni-ir-overlay.dtsi" +#include "qcs405-circular-pca9956.dtsi" / { model = "Qualcomm Technologies, Inc. QCS405 EVB1 4000 AMIC IOT"; diff --git a/arch/arm64/boot/dts/qcom/qcs405-linear-pca9956.dtsi b/arch/arm64/boot/dts/qcom/qcs405-linear-pca9956.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..cc872d4b4ebc659585a8010f0c085dd4ac15e217 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs405-linear-pca9956.dtsi @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&i2c_2 { + status = "ok"; + qcom,clk-freq-out = <100000>; + + /* PCA9956B LED Drivers */ + nxp-ledseg-i2c@65 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nxp,pca9956b"; + reg = <0x65>; + pca9956b,support_initialize = <1>; + pca9956b,mode1 = <0x09>; + pca9956b,mode2 = <0x05>; + + pca9956b,ledout0 = <0xAA>; + pca9956b,ledout1 = <0xAA>; + pca9956b,ledout2 = <0xAA>; + pca9956b,ledout3 = <0xFF>; + pca9956b,ledout4 = <0xFF>; + pca9956b,ledout5 = <0xFF>; + pca9956b,defaultiref = <0x2f>; + out0@0 { + label = "ledsec5_b"; + reg = <0x0>; + }; + out1@1 { + label = "ledsec5_g"; + reg = <0x1>; + }; + out2@2 { + label = "ledsec5_r"; + reg = <0x2>; + }; + out3@3 { + label = "ledsec6_b"; + reg = <0x3>; + }; + out4@4 { + label = "ledsec6_g"; + reg = <0x4>; + }; + out5@5 { + label = "ledsec6_r"; + reg = <0x5>; + }; + out6@6 { + label = "ledsec7_b"; + reg = <0x6>; + }; + out7@7 { + label = "ledsec7_g"; + reg = <0x7>; + }; + out8@8 { + label = "ledsec7_r"; + reg = <0x8>; + }; + out9@9 { + label = "ledsec8_b"; + reg = <0x9>; + }; + out10@10 { + label = "ledsec8_g"; + reg = <0xA>; + }; + out11@11 { + label = "ledsec8_r"; + reg = <0xB>; + }; + out12@12 { + label = "ledsec1_b"; + reg = <0xC>; + }; + out13@13 { + label = "ledsec1_g"; + reg = <0xD>; + }; + out14@14 { + label = "ledsec1_r"; + reg = <0xE>; + }; + out15@15 { + label = "ledsec2_b"; + reg = <0xF>; + }; + out16@16 { + label = "ledsec2_g"; + reg = <0x10>; + }; + out17@17 { + label = "ledsec2_r"; + reg = <0x11>; + }; + out18@18 { + label = "ledsec3_b"; + reg = <0x12>; + }; + out19@19 { + label = "ledsec3_g"; + reg = <0x13>; + }; + out20@20 { + label = "ledsec3_r"; + reg = <0x14>; + }; + out21@21 { + label = "ledsec4_b"; + reg = <0x15>; + }; + out22@22 { + label = "ledsec4_g"; + reg = <0x16>; + }; + out23@23 { + label = "ledsec4_r"; + reg = <0x17>; + }; + }; + + nxp-ledseg-i2c@15 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nxp,pca9956b"; + reg = <0x15>; + pca9956b,support_initialize = <1>; + pca9956b,mode1 = <0x09>; + pca9956b,mode2 = <0x05>; + + pca9956b,ledout0 = <0xAA>; + pca9956b,ledout1 = <0xAA>; + pca9956b,ledout2 = <0xAA>; + pca9956b,ledout3 = <0xFF>; + pca9956b,ledout4 = <0xFF>; + pca9956b,ledout5 = <0xFF>; + pca9956b,defaultiref = <0x2f>; + out0@0 { + label = "ledsec9_b"; + reg = <0x0>; + }; + out1@1 { + label = "ledsec9_g"; + reg = <0x1>; + }; + out2@2 { + label = "ledsec9_r"; + reg = <0x2>; + }; + out3@3 { + label = "ledsec10_b"; + reg = <0x3>; + }; + out4@4 { + label = "ledsec10_g"; + reg = <0x4>; + }; + out5@5 { + label = "ledsec10_r"; + reg = <0x5>; + }; + out6@6 { + label = "ledsec11_b"; + reg = <0x6>; + }; + out7@7 { + label = "ledsec11_g"; + reg = <0x7>; + }; + out8@8 { + label = "ledsec11_r"; + reg = <0x8>; + }; + out9@9 { + label = "ledsec12_b"; + reg = <0x9>; + }; + out10@10 { + label = "ledsec12_g"; + reg = <0xA>; + }; + out11@11 { + label = "ledsec12_r"; + reg = <0xB>; + }; + out12@12 { + label = "ledsec13_b"; + reg = <0xC>; + }; + out13@13 { + label = "ledsec13_g"; + reg = <0xD>; + }; + out14@14 { + label = "ledsec13_r"; + reg = <0xE>; + }; + out15@15 { + label = "ledsec14_b"; + reg = <0xF>; + }; + out16@16 { + label = "ledsec14_g"; + reg = <0x10>; + }; + out17@17 { + label = "ledsec14_r"; + reg = <0x11>; + }; + out18@18 { + label = "ledsec15_b"; + reg = <0x12>; + }; + out19@19 { + label = "ledsec15_g"; + reg = <0x13>; + }; + out20@20 { + label = "ledsec15_r"; + reg = <0x14>; + }; + out21@21 { + label = "ledsec16_b"; + reg = <0x15>; + }; + out22@22 { + label = "ledsec16_g"; + reg = <0x16>; + }; + out23@23 { + label = "ledsec16_r"; + reg = <0x17>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs405-mdss-pll.dtsi b/arch/arm64/boot/dts/qcom/qcs405-mdss-pll.dtsi index 31243496e78bda6a3bbe33e191b5f1f12962bb85..06e7d18e97bd87b8daf128134000ad901aea561f 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-mdss-pll.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-mdss-pll.dtsi @@ -83,4 +83,44 @@ }; }; }; + + mdss_hdmi_pll: qcom,mdss_hdmi_pll@0x1aa0600 { + compatible = "qcom,mdss_hdmi_pll_28lpm"; + label = "MDSS HDMI PLL"; + cell-index = <0>; + #clock-cells = <1>; + + reg = <0x1aa0600 0x49c>, + <0x0184d074 0x8>; + reg-names = "pll_base", "gdsc_base"; + + gdsc-supply = <&gdsc_mdss>; + vddx-pll-supply = <&pms405_l5>; + + clocks = <&clock_gcc GCC_MDSS_AHB_CLK>; + clock-names = "iface_clk"; + clock-rate = <0>; + + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + qcom,platform-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vddx-pll"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <14300>; + qcom,supply-disable-load = <1>; + }; + }; + }; }; diff --git a/arch/arm64/boot/dts/qcom/qcs405-mdss.dtsi b/arch/arm64/boot/dts/qcom/qcs405-mdss.dtsi index 09ad58f684ac97a255791bc09f2fe93b6896c3c1..d78813c1ef1c98f9aed8fb0318d5e2d783335fee 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-mdss.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-mdss.dtsi @@ -193,12 +193,13 @@ compatible = "qcom,mdss-fb"; }; - mdss_fb1: qcom,mdss_fb_wfd { + mdss_fb1: qcom,mdss_fb_hdmi { cell-index = <1>; compatible = "qcom,mdss-fb"; + qcom,mdss-intf = <&mdss_hdmi_tx>; }; - mdss_fb2: qcom,mdss_fb_secondary { + mdss_fb2: qcom,mdss_fb_wfd { cell-index = <2>; compatible = "qcom,mdss-fb"; }; @@ -242,8 +243,6 @@ qcom,mmss-phyreset-ctrl-offset = <0x24>; qcom,mdss-fb-map-prim = <&mdss_fb0>; - qcom,mdss-fb-map-sec = <&mdss_fb2>; - /*qcom,mdss-fb-map = <&mdss_fb0>;*/ qcom,core-supply-entries { #address-cells = <1>; #size-cells = <0>; @@ -322,11 +321,55 @@ }; }; + msm_ext_disp: qcom,msm_ext_disp { + compatible = "qcom,msm-ext-disp"; + + ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx { + compatible = "qcom,msm-ext-disp-audio-codec-rx"; + qcom,msm_ext_disp = <&msm_ext_disp>; + }; + }; + + mdss_hdmi_tx: qcom,hdmi_tx@1aa0000 { + cell-index = <0>; + compatible = "qcom,hdmi-tx"; + + reg = <0x1aa0000 0x50c>, + <0xa0000 0x6400>, + <0x1ae0000 0x28>; + reg-names = "core_physical", "qfprom_physical", "hdcp_physical"; + + hpd-gdsc-supply = <&gdsc_mdss>; + + qcom,supply-names = "hpd-gdsc"; + qcom,min-voltage-level = <0>; + qcom,max-voltage-level = <0>; + qcom,enable-load = <0>; + qcom,disable-load = <0>; + + qcom,msm_ext_disp = <&msm_ext_disp>; + + clocks = <&clock_gcc GCC_MDSS_AHB_CLK>, + <&clock_gcc_mdss MDSS_MDP_VOTE_CLK>, + <&clock_gcc GCC_MDSS_HDMI_APP_CLK>, + <&clock_gcc GCC_MDSS_HDMI_PCLK_CLK>, + <&clock_gcc HDMI_PCLK_CLK_SRC>, + <&mdss_hdmi_pll HDMI_PCLK_SRC>; + + clock-names = "hpd_iface_clk", "hpd_mdp_core_clk", + "hpd_core_clk", "core_extp_clk", + "hdmi_pclk_rcg", "ext_hdmi_pixel_clk"; + + qcom,mdss-fb-map = <&mdss_fb1>; + qcom,pluggable; + qcom,max-pclk-frequency-khz = <148500>; + }; + qcom,mdss_wb_panel { compatible = "qcom,mdss_wb"; qcom,mdss_pan_res = <640 640>; qcom,mdss_pan_bpp = <24>; - qcom,mdss-fb-map = <&mdss_fb1>; + qcom,mdss-fb-map = <&mdss_fb2>; }; }; diff --git a/arch/arm64/boot/dts/qcom/qcs405-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/qcs405-pinctrl.dtsi index c923904f5c05eec91a2a32547b284e67278aa170..e8abebb0c2ea671cd1ffcea8fd9bea447e5c27f4 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-pinctrl.dtsi @@ -15,6 +15,7 @@ tlmm: pinctrl@1000000 { compatible = "qcom,qcs405-pinctrl"; reg = <0x1000000 0x200000>; + reg-names = "pinctrl"; interrupts-extended = <&wakegic GIC_SPI 208 IRQ_TYPE_NONE>; gpio-controller; #gpio-cells = <2>; @@ -686,6 +687,110 @@ }; }; + mdss_hdmi_5v_active: mdss_hdmi_5v_active { + mux { + pins = "gpio109"; + function = "gpio"; + }; + + config { + pins = "gpio109"; + bias-pull-up; + drive-strength = <16>; + }; + }; + + mdss_hdmi_5v_suspend: mdss_hdmi_5v_suspend { + mux { + pins = "gpio109"; + function = "gpio"; + }; + + config { + pins = "gpio109"; + bias-pull-down; + drive-strength = <2>; + }; + }; + + mdss_hdmi_hpd_active: mdss_hdmi_hpd_active { + mux { + pins = "gpio106"; + function = "hdmi_hot"; + }; + + config { + pins = "gpio106"; + bias-pull-down; + drive-strength = <16>; + }; + }; + + mdss_hdmi_hpd_suspend: mdss_hdmi_hpd_suspend { + mux { + pins = "gpio106"; + function = "hdmi_hot"; + }; + + config { + pins = "gpio106"; + bias-pull-down; + drive-strength = <2>; + }; + }; + + mdss_hdmi_ddc_active: mdss_hdmi_ddc_active { + mux { + pins = "gpio15", "gpio16"; + function = "hdmi_ddc"; + }; + + config { + pins = "gpio15", "gpio16"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + mdss_hdmi_ddc_suspend: mdss_hdmi_ddc_suspend { + mux { + pins = "gpio15", "gpio16"; + function = "hdmi_ddc"; + }; + + config { + pins = "gpio15", "gpio16"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + mdss_hdmi_cec_active: mdss_hdmi_cec_active { + mux { + pins = "gpio14"; + function = "hdmi_cec"; + }; + + config { + pins = "gpio14"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + mdss_hdmi_cec_suspend: mdss_hdmi_cec_suspend { + mux { + pins = "gpio14"; + function = "hdmi_cec"; + }; + + config { + pins = "gpio14"; + drive-strength = <2>; + bias-pull-up; + }; + }; + pmx_mdss: pmx_mdss { mdss_dsi_active: mdss_dsi_active { mux { @@ -884,6 +989,20 @@ }; }; + nxp_i2c_intr: nxp_i2c_intr { + mux { + pins = "gpio35"; + function = "gpio"; + }; + + config { + pins = "gpio35"; + drive-strength = <2>; + bias-pull-up; + input-enable; + }; + }; + usb3_id_det_default: usb2_id_det_default { config { pins = "gpio116"; @@ -1791,5 +1910,37 @@ }; }; }; + + evb_tlmm_gpio_key{ + tlmm_gpio_key_active: tlmm_gpio_key_active { + mux { + pins = "gpio21","gpio52","gpio54", + "gpio115"; + function = "gpio"; + }; + + config { + pins = "gpio21","gpio52","gpio54", + "gpio115"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + tlmm_gpio_key_suspend: tlmm_gpio_key_suspend { + mux { + pins = "gpio21","gpio52","gpio54", + "gpio115"; + function = "gpio"; + }; + + config { + pins = "gpio21","gpio52","gpio54", + "gpio115"; + drive-strength = <2>; + bias-disable; + }; + }; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/qcs405-tdm-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/qcs405-tdm-audio-overlay.dtsi index 5505f583a71c04fb3bb3e10cf241ce9f9bfe8b4d..ab43fd8efff9357c870ac9ae77c123632de7c947 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-tdm-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-tdm-audio-overlay.dtsi @@ -56,6 +56,8 @@ &tdm_quin_tx { qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; }; &soc { diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index fd78a51bc15efe39bb56c2cf2b4d0f7ecf4cf457..725fba0a48bc377497b6e672bc572b294d1e0540 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -748,7 +748,7 @@ qcom,msm-mdf-mem { compatible = "qcom,msm-mdf-mem-region"; - qcom,msm-mdf-mem-data-size = <0x200000>; + qcom,msm-mdf-mem-data-size = <0x800000>; memory-region = <&mdf_mem>; }; @@ -1460,6 +1460,16 @@ dpdm-supply = <&usb2_phy0>; qcom,otg-enable; }; + + usb_typec: usb_typec@3d { + compatible = "nxp,5150a"; + reg = <0x3d>; + interrupt-parent = <&tlmm>; + interrupts = <35 IRQ_TYPE_LEVEL_LOW>; + pintctrl-names = "default"; + pinctrl-0 = <&nxp_i2c_intr>; + status = "disabled"; + }; }; &pms405_gpios { @@ -1501,29 +1511,52 @@ extcon = <&usb3_extcon>; }; -#include "qcs405-led-pca9956.dtsi" - &soc { - i2c_2: i2c@78b6000 { /* BLSP1 QUP2 */ - compatible = "qcom,i2c-msm-v2"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x78b6000 0x600>; - reg-names = "qup_phys_addr"; - interrupt-names = "qup_irq"; - interrupts = <0 96 0>; - dmas = <&dma_blsp1 10 64 0x20000020 0x20>, - <&dma_blsp1 11 32 0x20000020 0x20>; - dma-names = "tx", "rx"; - qcom,master-id = <86>; - qcom,clk-freq-out = <400000>; - qcom,clk-freq-in = <19200000>; - clock-names = "iface_clk", "core_clk"; - clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, - <&clock_gcc GCC_BLSP1_QUP1_I2C_APPS_CLK>; - pinctrl-names = "i2c_active", "i2c_sleep"; - pinctrl-0 = <&i2c_2_active &pca9956b_reset_gpio>; - pinctrl-1 = <&i2c_2_sleep>; - status = "ok"; + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + input-name = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&tlmm_gpio_key_active>; + + vol_mute { + label = "vol_mute"; + gpios = <&tlmm 21 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + debounce-interval = <15>; + gpio-key,wakeup; + linux,can-disable; + }; + + vol_down { + label = "vol_down"; + gpios = <&tlmm 54 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + debounce-interval = <15>; + gpio-key,wakeup; + linux,can-disable; + }; + + vol_up { + label = "vol_up"; + gpios = <&tlmm 52 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + debounce-interval = <15>; + gpio-key,wakeup; + linux,can-disable; + }; + + home { + label = "action"; + gpios = <&tlmm 115 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + debounce-interval = <15>; + gpio-key,wakeup; + linux,can-disable; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/qg-batterydata-alium-3600mah.dtsi b/arch/arm64/boot/dts/qcom/qg-batterydata-alium-3600mah.dtsi index 80dd60172819b5bc8e91ecf66d3d49335b4fcd9c..0b6935b6478b8b30b534860586954e173dc4087c 100644 --- a/arch/arm64/boot/dts/qcom/qg-batterydata-alium-3600mah.dtsi +++ b/arch/arm64/boot/dts/qcom/qg-batterydata-alium-3600mah.dtsi @@ -28,9 +28,10 @@ qcom,alium_860_89032_0000_3600mAh { qcom,jeita-fv-ranges = <0 50 4250000 60 400 4350000 410 450 4250000>; - qcom,step-chg-ranges = <3600000 4200000 5400000 - 4201000 4300000 3600000 + qcom,step-chg-ranges = <3600000 3800000 5400000 + 3801000 4300000 3600000 4301000 4350000 2500000>; + qcom,ocv-based-step-chg; /* COOL = 5 DegC, WARM = 40 DegC */ qcom,jeita-soft-thresholds = <0x5314 0x25e3>; diff --git a/arch/arm64/boot/dts/qcom/qg-batterydata-mlp466076-3200mah.dtsi b/arch/arm64/boot/dts/qcom/qg-batterydata-mlp466076-3200mah.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..30a355683891f1d7a8e01738a15706813a596299 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qg-batterydata-mlp466076-3200mah.dtsi @@ -0,0 +1,1040 @@ + +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +qcom,mlp466076_3200mAh { + /* mlp466076_3200mAh_averaged_MasterSlave_Sept28th2018 */ + qcom,max-voltage-uv = <4400000>; + qcom,fg-cc-cv-threshold-mv = <4390>; + qcom,fastchg-current-ma = <6000>; + qcom,batt-id-kohm = <133>; + qcom,battery-beta = <4250>; + qcom,battery-therm-kohm = <100>; + qcom,battery-type = + "mlp466076_3200mAh_averaged_MasterSlave_Sept28th2018"; + qcom,qg-batt-profile-ver = <100>; + + qcom,jeita-fcc-ranges = <0 150 650000 + 151 450 4875000 + 451 550 1625000>; + qcom,jeita-fv-ranges = <0 150 4150000 + 151 450 4400000 + 451 550 4150000>; + /* COLD = 0 DegC, HOT = 55 DegC */ + qcom,jeita-hard-thresholds = <0x5840 0x1810>; + /* COOL = 15 DegC, WARM = 45 DegC */ + qcom,jeita-soft-thresholds = <0x45f3 0x20c4>; + + qcom,fcc1-temp-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-data = <3205 3248 3306 3328 3328>; + }; + + qcom,fcc2-temp-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-data = <3118 3203 3253 3314 3327 3333>; + }; + + qcom,pc-temp-v1-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <43662 43765 43827 43854 43857>, + <43465 43592 43648 43679 43680>, + <43244 43371 43441 43477 43474>, + <43004 43143 43219 43263 43254>, + <42786 42919 42991 43039 43024>, + <42603 42692 42762 42806 42790>, + <42425 42464 42530 42568 42557>, + <42215 42239 42301 42330 42326>, + <41980 42016 42073 42096 42101>, + <41759 41797 41849 41866 41875>, + <41557 41584 41627 41642 41650>, + <41362 41378 41411 41424 41428>, + <41163 41178 41202 41209 41210>, + <40961 40977 41001 40999 40999>, + <40760 40772 40799 40794 40793>, + <40563 40570 40594 40597 40597>, + <40358 40372 40396 40405 40407>, + <40145 40178 40221 40225 40226>, + <39945 40002 40053 40053 40050>, + <39789 39854 39847 39858 39853>, + <39654 39711 39576 39612 39620>, + <39531 39519 39339 39375 39391>, + <39412 39263 39176 39190 39200>, + <39282 39052 39040 39032 39031>, + <39133 38917 38919 38892 38884>, + <38984 38816 38812 38767 38758>, + <38858 38736 38712 38655 38645>, + <38756 38672 38614 38553 38541>, + <38668 38609 38524 38459 38444>, + <38595 38544 38445 38374 38354>, + <38533 38483 38374 38297 38270>, + <38475 38429 38310 38226 38195>, + <38430 38379 38253 38166 38130>, + <38401 38330 38199 38107 38067>, + <38377 38287 38153 38049 38003>, + <38346 38242 38109 37990 37936>, + <38285 38194 38057 37927 37867>, + <38212 38141 37997 37860 37794>, + <38144 38070 37923 37783 37713>, + <38069 37964 37822 37685 37612>, + <37974 37836 37698 37571 37495>, + <37837 37691 37560 37439 37359>, + <37673 37537 37406 37289 37206>, + <37502 37409 37248 37138 37064>, + <37345 37284 37128 37023 36958>, + <37238 37184 37066 36969 36904>, + <37204 37151 37050 36949 36887>, + <37171 37121 37032 36932 36873>, + <37134 37087 36999 36898 36835>, + <37025 36967 36850 36728 36642>, + <36701 36632 36509 36379 36285>, + <36239 36167 36048 35916 35824>, + <35649 35576 35460 35327 35236>, + <34852 34778 34666 34533 34443>, + <33622 33561 33462 33330 33238>, + <30000 30000 30000 30000 30000>; + }; + + qcom,pc-temp-v2-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <43390 43645 43750 43815 43800 43795>, + <42983 43258 43441 43569 43578 43582>, + <42608 42904 43149 43327 43354 43366>, + <42270 42588 42877 43089 43129 43145>, + <41961 42304 42623 42856 42904 42921>, + <41683 42042 42377 42623 42676 42694>, + <41438 41791 42134 42391 42446 42463>, + <41238 41546 41897 42160 42215 42232>, + <41062 41317 41666 41934 41987 42003>, + <40846 41113 41438 41710 41760 41775>, + <40569 40968 41219 41489 41537 41550>, + <40319 40809 41018 41270 41319 41329>, + <40103 40562 40827 41057 41104 41111>, + <39844 40259 40633 40856 40895 40900>, + <39546 39953 40421 40658 40689 40693>, + <39304 39745 40200 40455 40490 40494>, + <39117 39574 39983 40245 40297 40302>, + <38956 39378 39768 40043 40107 40114>, + <38793 39156 39546 39861 39925 39933>, + <38644 38938 39315 39676 39735 39743>, + <38519 38742 39102 39446 39499 39505>, + <38411 38566 38911 39183 39234 39243>, + <38324 38421 38746 38973 39029 39041>, + <38257 38302 38600 38817 38875 38887>, + <38199 38211 38469 38683 38741 38752>, + <38146 38145 38351 38560 38617 38628>, + <38098 38091 38245 38450 38505 38515>, + <38052 38045 38150 38347 38400 38409>, + <38006 38004 38065 38253 38304 38311>, + <37961 37964 37993 38163 38214 38219>, + <37916 37925 37937 38080 38133 38135>, + <37869 37885 37889 38001 38057 38057>, + <37819 37842 37844 37926 37987 37985>, + <37765 37793 37800 37855 37919 37914>, + <37706 37743 37753 37784 37834 37819>, + <37641 37692 37702 37716 37722 37690>, + <37572 37633 37642 37647 37608 37564>, + <37495 37562 37573 37569 37511 37461>, + <37414 37476 37492 37486 37421 37368>, + <37330 37382 37399 37399 37334 37278>, + <37241 37277 37290 37309 37247 37186>, + <37150 37164 37167 37199 37139 37073>, + <37061 37043 37037 37065 37012 36948>, + <36974 36929 36917 36918 36864 36803>, + <36874 36836 36835 36850 36812 36762>, + <36760 36750 36766 36819 36788 36738>, + <36690 36703 36735 36797 36767 36721>, + <36594 36645 36672 36765 36742 36693>, + <36441 36551 36563 36683 36669 36598>, + <36215 36353 36313 36466 36433 36312>, + <35901 36016 35927 36050 36018 35886>, + <35430 35532 35419 35522 35495 35356>, + <34781 34891 34751 34850 34822 34674>, + <33883 34005 33839 33929 33926 33799>, + <32534 32590 32567 32727 32712 32584>, + <30011 30004 30001 30000 30000 29999>; + }; + + qcom,pc-temp-z1-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <13336 12737 12245 12063 12028>, + <13321 12715 12202 12029 11977>, + <13325 12709 12216 11985 11908>, + <13384 12694 12186 11976 11728>, + <13496 12676 12160 11969 11639>, + <13923 12659 12154 11893 11631>, + <14348 12649 12151 11776 11626>, + <14398 12645 12146 11753 11623>, + <14405 12639 12138 11752 11620>, + <14400 12606 12131 11751 11617>, + <14362 12571 12127 11749 11615>, + <14304 12567 12126 11745 11614>, + <14258 12571 12126 11742 11613>, + <14214 12572 12126 11740 11610>, + <14183 12588 12124 11738 11609>, + <14141 12697 12117 11737 11609>, + <14075 12810 12113 11737 11609>, + <14011 12906 12116 11737 11610>, + <13963 12974 12123 11738 11610>, + <13946 12991 12124 11740 11610>, + <13939 12997 12122 11742 11610>, + <13933 12991 12120 11744 11612>, + <13934 12994 12127 11747 11614>, + <13946 13005 12137 11750 11617>, + <13955 13003 12140 11754 11620>, + <13948 12997 12140 11759 11622>, + <13954 12995 12141 11762 11626>, + <13959 12996 12143 11764 11629>, + <13950 12997 12146 11765 11633>, + <13956 13000 12149 11768 11637>, + <13993 13006 12155 11775 11641>, + <14015 13018 12157 11780 11645>, + <14022 13035 12158 11783 11649>, + <14016 13041 12160 11786 11653>, + <14003 13041 12168 11789 11656>, + <13991 13044 12179 11793 11660>, + <13999 13058 12183 11799 11664>, + <14034 13080 12184 11809 11669>, + <14066 13093 12185 11817 11674>, + <14095 13109 12200 11820 11679>, + <14119 13123 12216 11822 11684>, + <14122 13124 12214 11823 11687>, + <14096 13124 12204 11830 11690>, + <14077 13123 12206 11831 11693>, + <14091 13131 12216 11832 11695>, + <14132 13134 12220 11839 11701>, + <14111 13151 12226 11842 11703>, + <14099 13131 12231 11845 11707>, + <14137 13170 12238 11848 11710>, + <14113 13167 12233 11864 11717>, + <14164 13173 12257 11862 11720>, + <14159 13211 12252 11883 11727>, + <14137 13247 12286 11882 11736>, + <14149 13284 12290 11888 11745>, + <14149 13284 12290 11888 11745>, + <14149 13284 12290 11888 11745>; + }; + + qcom,pc-temp-z2-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <9618 9833 10273 10587 10613>, + <9717 10071 10235 10423 10322>, + <9767 10199 10360 10416 10359>, + <10027 10256 10382 10432 10417>, + <10146 10256 10391 10426 10403>, + <9854 10234 10380 10416 10359>, + <9540 10218 10359 10403 10313>, + <9614 10214 10345 10400 10300>, + <9875 10209 10334 10415 10313>, + <9964 10204 10329 10423 10330>, + <9958 10204 10339 10396 10336>, + <9950 10208 10353 10348 10338>, + <9946 10211 10359 10338 10339>, + <9943 10216 10362 10358 10338>, + <9910 10210 10368 10373 10337>, + <9742 10146 10380 10369 10343>, + <9638 10109 10390 10356 10357>, + <9760 10123 10389 10353 10377>, + <9935 10139 10383 10357 10397>, + <9965 10142 10386 10365 10410>, + <9980 10142 10400 10404 10416>, + <10008 10144 10410 10463 10423>, + <9880 10150 10391 10527 10467>, + <9720 10157 10363 10588 10536>, + <9779 10171 10371 10588 10530>, + <9972 10186 10419 10538 10402>, + <10034 10188 10442 10493 10311>, + <10027 10183 10423 10474 10309>, + <10024 10181 10403 10462 10323>, + <10022 10188 10403 10460 10329>, + <10021 10197 10406 10460 10328>, + <10020 10201 10411 10461 10334>, + <10019 10205 10425 10482 10364>, + <9912 10208 10438 10519 10399>, + <9718 10212 10445 10557 10436>, + <9686 10216 10450 10599 10488>, + <9872 10220 10457 10630 10512>, + <10038 10226 10465 10653 10510>, + <9970 10229 10473 10670 10510>, + <9661 10232 10488 10685 10521>, + <9424 10234 10501 10695 10542>, + <9380 10229 10497 10686 10581>, + <9360 10221 10485 10657 10635>, + <9344 10401 10482 10661 10609>, + <9319 11186 10491 10661 10585>, + <9305 13142 10504 10625 10613>, + <9304 13559 10476 10620 10613>, + <9293 12008 10464 10612 10648>, + <9279 11863 10466 10654 10747>, + <9266 12115 10555 10704 10597>, + <9244 11992 10590 10647 10489>, + <9219 10653 10578 10583 10440>, + <9180 10297 10596 10530 10382>, + <9154 9949 10524 10471 10317>, + <9154 9949 10524 10471 10317>, + <9154 9949 10524 10471 10317>; + }; + + qcom,pc-temp-z3-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <19375 19363 19375 19346 19348>, + <19394 19375 19412 19383 19378>, + <19468 19500 19455 19415 19392>, + <19623 19565 19476 19435 19361>, + <19700 19580 19486 19440 19348>, + <19658 19588 19489 19420 19361>, + <19609 19591 19491 19387 19372>, + <19662 19591 19490 19383 19370>, + <19814 19591 19488 19389 19364>, + <19862 19588 19485 19390 19359>, + <19847 19579 19478 19384 19358>, + <19826 19569 19471 19377 19357>, + <19811 19561 19468 19374 19357>, + <19800 19556 19465 19374 19356>, + <19764 19563 19463 19374 19354>, + <19601 19599 19463 19372 19350>, + <19493 19623 19463 19370 19346>, + <19603 19630 19460 19369 19343>, + <19740 19634 19456 19368 19342>, + <19729 19629 19457 19367 19342>, + <19717 19622 19467 19370 19344>, + <19700 19624 19473 19373 19349>, + <19575 19644 19462 19377 19360>, + <19507 19655 19447 19383 19375>, + <19642 19654 19449 19389 19380>, + <19829 19652 19464 19402 19380>, + <19889 19647 19475 19411 19380>, + <19884 19641 19480 19408 19376>, + <19880 19639 19483 19403 19371>, + <19873 19638 19481 19398 19368>, + <19863 19638 19475 19393 19365>, + <19854 19636 19471 19388 19362>, + <19843 19634 19468 19385 19358>, + <19752 19632 19465 19381 19355>, + <19596 19631 19462 19379 19352>, + <19561 19629 19459 19378 19349>, + <19674 19626 19457 19377 19348>, + <19773 19619 19455 19377 19347>, + <19709 19612 19453 19377 19346>, + <19460 19605 19449 19376 19347>, + <19282 19598 19443 19373 19349>, + <19273 19594 19440 19370 19351>, + <19274 19589 19438 19367 19354>, + <19274 19383 19434 19366 19352>, + <19275 19258 19424 19363 19345>, + <19276 19257 19403 19344 19332>, + <19276 19257 19383 19344 19331>, + <19277 19258 19361 19345 19324>, + <19278 19258 19366 19342 19319>, + <19279 19258 19361 19347 19341>, + <19281 19258 19350 19351 19347>, + <19284 19259 19346 19357 19349>, + <19291 19260 19336 19360 19351>, + <19296 19262 19330 19362 19356>, + <19296 19262 19330 19362 19356>, + <19296 19262 19330 19362 19356>; + }; + + qcom,pc-temp-z4-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <15630 15273 15043 14960 14945>, + <15689 15382 15065 14963 14961>, + <15723 15346 15157 15020 14973>, + <15654 15257 15080 15001 14877>, + <15621 15154 14988 14931 14792>, + <15743 15055 14927 14858 14759>, + <15853 14981 14873 14788 14737>, + <15756 14922 14829 14752 14722>, + <15538 14876 14792 14733 14715>, + <15404 14844 14769 14721 14709>, + <15340 14819 14759 14716 14702>, + <15293 14799 14752 14713 14694>, + <15250 14783 14746 14708 14686>, + <15214 14773 14740 14701 14680>, + <15227 14774 14739 14695 14676>, + <15369 14801 14741 14692 14673>, + <15468 14820 14744 14690 14671>, + <15361 14830 14738 14688 14670>, + <15201 14832 14727 14685 14667>, + <15170 14815 14736 14690 14675>, + <15151 14789 14815 14750 14721>, + <15127 14804 14877 14806 14764>, + <15219 14885 14892 14809 14763>, + <15278 14938 14900 14802 14751>, + <15140 14940 14888 14791 14740>, + <14941 14935 14845 14762 14727>, + <14880 14921 14812 14737 14714>, + <14888 14894 14794 14726 14706>, + <14891 14871 14782 14720 14700>, + <14891 14857 14780 14716 14695>, + <14888 14844 14779 14715 14691>, + <14884 14834 14779 14714 14689>, + <14879 14825 14781 14714 14688>, + <14953 14818 14783 14714 14687>, + <15095 14813 14783 14718 14692>, + <15118 14807 14782 14727 14704>, + <14978 14801 14782 14731 14709>, + <14853 14795 14780 14732 14711>, + <14902 14789 14778 14733 14711>, + <15140 14785 14771 14729 14708>, + <15315 14780 14761 14722 14703>, + <15314 14769 14752 14717 14701>, + <15291 14758 14742 14712 14699>, + <15259 14934 14730 14706 14695>, + <15156 15013 14704 14693 14685>, + <15078 14949 14666 14661 14654>, + <15075 14945 14675 14647 14643>, + <15071 14942 14689 14634 14634>, + <15063 14935 14681 14635 14635>, + <15049 14927 14694 14647 14637>, + <15057 14938 14712 14649 14640>, + <15071 14942 14718 14646 14641>, + <15084 14949 14731 14644 14640>, + <15105 14958 14742 14645 14638>, + <15105 14958 14742 14645 14638>, + <15105 14958 14742 14645 14638>; + }; + + qcom,pc-temp-z5-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <12124 12072 13157 13174 13606>, + <12994 13000 14804 15085 15154>, + <13587 14583 15791 16396 16870>, + <13874 15964 16772 16919 15801>, + <13884 16939 17839 17371 16041>, + <13288 17849 18811 17290 17992>, + <12752 18889 19806 17211 20051>, + <13155 20252 21035 17957 20337>, + <14211 21670 22602 19862 19980>, + <14723 22477 23646 20935 19733>, + <14736 22953 24200 20677 20042>, + <14649 23096 24568 19994 20872>, + <14721 23386 24733 19863 21792>, + <14828 23940 25087 20680 22627>, + <14648 25256 25600 21530 22979>, + <13383 26083 27040 21835 22568>, + <12564 25447 28188 22062 21924>, + <14450 24954 27982 22511 21937>, + <16825 25408 27494 23231 22542>, + <16732 25757 28143 23429 22575>, + <16303 26250 33310 22605 21080>, + <15711 28817 36779 21685 19879>, + <13993 36697 31028 20502 19380>, + <16429 41291 22626 18349 18894>, + <23300 39174 21659 17982 18992>, + <29454 35310 22858 20629 20165>, + <31867 32664 24466 23458 21295>, + <32326 30650 27410 25252 22111>, + <32352 30008 30586 26767 23020>, + <31698 30713 32388 28065 24313>, + <30597 31769 33715 29167 26079>, + <29641 32615 34902 30229 27629>, + <28570 33593 36165 31554 29266>, + <25166 34668 36865 32469 30251>, + <20184 36022 36864 32454 29500>, + <18967 36995 36786 32263 28117>, + <21737 37027 36538 32001 27361>, + <24117 36857 35657 31514 25956>, + <22175 36546 34649 30833 24906>, + <15699 35485 33710 29804 25141>, + <11242 34238 32735 28436 25578>, + <10985 33611 31645 26834 26096>, + <10984 32850 30651 25139 26981>, + <10998 19087 30705 25214 25567>, + <11145 11243 30585 25077 23501>, + <11257 11255 29211 23396 23355>, + <11216 11222 22088 26638 26212>, + <11217 11211 16895 30416 25864>, + <11223 11229 17933 28658 22675>, + <11260 11323 17117 24401 28538>, + <11268 11309 15536 23343 28235>, + <11186 11276 14888 24817 26689>, + <11117 11246 13952 24826 26557>, + <11073 11186 13396 24230 27076>, + <11073 11186 13396 24230 27076>, + <11073 11186 13396 24230 27076>; + }; + + qcom,pc-temp-z6-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <16016 15401 15028 14870 14848>, + <15996 15430 15032 14874 14857>, + <16013 15428 15075 14902 14845>, + <16033 15402 15037 14897 14721>, + <16086 15344 14991 14863 14651>, + <16361 15274 14956 14789 14644>, + <16617 15223 14923 14701 14637>, + <16582 15181 14896 14678 14629>, + <16509 15146 14871 14671 14622>, + <16437 15116 14854 14665 14616>, + <16363 15091 14843 14658 14611>, + <16293 15068 14836 14652 14607>, + <16231 15048 14830 14648 14603>, + <16173 15033 14826 14645 14600>, + <16114 15039 14823 14642 14596>, + <16055 15104 14821 14639 14593>, + <16013 15166 14819 14636 14590>, + <15987 15206 14815 14635 14588>, + <15960 15231 14810 14633 14587>, + <15927 15226 14815 14636 14590>, + <15890 15215 14856 14663 14611>, + <15856 15224 14886 14690 14632>, + <15831 15272 14888 14694 14639>, + <15823 15302 14886 14695 14642>, + <15833 15304 14882 14695 14642>, + <15847 15302 14874 14690 14637>, + <15856 15296 14868 14684 14631>, + <15863 15284 14864 14679 14625>, + <15866 15276 14862 14675 14621>, + <15866 15272 14861 14671 14617>, + <15865 15269 14859 14668 14615>, + <15862 15267 14859 14666 14613>, + <15859 15265 14860 14665 14610>, + <15852 15265 14861 14664 14609>, + <15844 15268 14863 14666 14610>, + <15842 15271 14865 14670 14614>, + <15848 15272 14866 14673 14617>, + <15853 15272 14868 14675 14618>, + <15851 15272 14869 14676 14618>, + <15844 15275 14867 14675 14618>, + <15839 15279 14864 14672 14617>, + <15842 15282 14863 14669 14618>, + <15846 15284 14862 14667 14620>, + <15845 15274 14860 14666 14618>, + <15825 15253 14851 14661 14611>, + <15802 15242 14830 14638 14592>, + <15802 15243 14825 14633 14586>, + <15804 15246 14823 14629 14579>, + <15809 15251 14826 14629 14578>, + <15817 15257 14834 14638 14591>, + <15831 15272 14842 14644 14598>, + <15851 15287 14848 14648 14600>, + <15875 15306 14857 14652 14603>, + <15910 15332 14869 14657 14608>, + <15910 15332 14869 14657 14608>, + <15910 15332 14869 14657 14608>; + }; + + qcom,pc-temp-y1-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <7469 6760 6042 5497 5274 5198>, + <7455 6707 6039 5495 5279 5198>, + <7446 6674 6036 5493 5282 5198>, + <7441 6657 6033 5492 5283 5196>, + <7439 6651 6030 5492 5282 5194>, + <7438 6650 6029 5492 5281 5191>, + <7435 6671 6029 5490 5278 5188>, + <7457 6694 6031 5488 5274 5184>, + <7493 6691 6032 5488 5271 5182>, + <7523 6673 6036 5489 5269 5179>, + <7534 6667 6039 5489 5266 5178>, + <7533 6670 6042 5486 5262 5176>, + <7509 6674 6043 5484 5260 5175>, + <7462 6673 6041 5488 5259 5174>, + <7430 6668 6043 5496 5258 5173>, + <7429 6670 6047 5497 5257 5173>, + <7440 6686 6046 5494 5255 5172>, + <7451 6697 6045 5491 5254 5172>, + <7461 6689 6051 5490 5254 5171>, + <7470 6688 6064 5489 5254 5171>, + <7467 6709 6073 5490 5254 5172>, + <7453 6738 6074 5493 5256 5173>, + <7447 6737 6069 5494 5257 5174>, + <7466 6706 6057 5493 5258 5174>, + <7488 6684 6045 5492 5259 5175>, + <7488 6689 6045 5497 5260 5176>, + <7479 6704 6053 5504 5261 5179>, + <7481 6706 6065 5507 5263 5180>, + <7480 6690 6067 5505 5266 5180>, + <7474 6678 6068 5504 5269 5181>, + <7470 6685 6071 5506 5271 5183>, + <7475 6700 6068 5510 5272 5186>, + <7487 6701 6058 5510 5274 5188>, + <7506 6693 6054 5511 5278 5190>, + <7505 6688 6053 5514 5282 5193>, + <7479 6697 6054 5525 5287 5196>, + <7461 6709 6058 5534 5290 5198>, + <7474 6706 6065 5532 5290 5201>, + <7509 6692 6071 5525 5289 5204>, + <7535 6679 6068 5523 5290 5206>, + <7557 6670 6052 5530 5294 5207>, + <7562 6667 6053 5530 5299 5210>, + <7500 6668 6060 5522 5304 5215>, + <7457 6704 6072 5530 5307 5216>, + <7452 6712 6072 5531 5305 5219>, + <7456 6691 6057 5530 5309 5222>, + <7457 6715 6070 5540 5311 5222>, + <7463 6729 6073 5535 5310 5225>, + <7518 6729 6079 5539 5324 5221>, + <7582 6694 6086 5548 5318 5222>, + <7580 6700 6062 5567 5316 5228>, + <7670 6739 6071 5571 5325 5234>, + <7673 6736 6087 5567 5337 5241>, + <7747 6806 6107 5572 5339 5245>, + <7747 6806 6107 5572 5339 5245>, + <7747 6806 6107 5572 5339 5245>; + }; + + qcom,pc-temp-y2-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <9654 9670 10551 11010 11144 11132>, + <9654 9664 10572 11003 11122 11113>, + <9654 9666 10596 10986 11100 11091>, + <9655 9674 10618 10965 11080 11067>, + <9655 9685 10634 10947 11062 11042>, + <9655 9700 10639 10938 11050 11014>, + <9655 9826 10635 10918 11042 10979>, + <9655 9962 10629 10897 11034 10951>, + <9656 9921 10625 10894 11006 10941>, + <9656 9908 10620 10889 10959 10936>, + <9655 10020 10617 10888 10942 10937>, + <9655 10154 10637 10888 10942 10942>, + <9656 10128 10673 10889 10944 10946>, + <9655 9942 10721 10887 10956 10950>, + <9655 9749 10784 10886 10981 10953>, + <9655 9706 10811 10900 11006 10948>, + <9655 9705 10823 10951 11037 10930>, + <9655 9700 10828 11000 11067 10930>, + <9655 9692 10813 11041 11113 11023>, + <9655 9685 10791 11070 11148 11118>, + <9655 9680 10790 11066 11141 11127>, + <9655 9676 10807 11047 11122 11129>, + <9655 9674 10824 11039 11127 11139>, + <9654 9674 10780 11055 11159 11171>, + <9654 9673 10518 11070 11188 11189>, + <9654 9671 10349 11080 11202 11180>, + <9654 9669 10440 11101 11206 11175>, + <9654 9666 10556 11106 11215 11189>, + <9654 9665 10441 11109 11252 11206>, + <9654 9663 10297 11110 11284 11234>, + <9654 9661 10243 11114 11292 11309>, + <9654 9660 10211 11117 11300 11366>, + <9654 9659 10170 11102 11321 11364>, + <9654 9657 10101 11060 11352 11337>, + <9654 9656 9980 11044 11359 11314>, + <9654 9656 9877 11079 11336 11289>, + <9654 9655 9821 11113 11306 11280>, + <9654 9654 9774 11098 11289 11291>, + <9654 9654 9727 11051 11276 11300>, + <9654 9654 9699 11010 11276 11302>, + <9654 9654 9686 10969 11341 11310>, + <9654 9653 9680 10925 11388 11308>, + <9654 9653 9674 10873 11365 11311>, + <9654 9653 9668 10788 11287 11336>, + <9653 9653 9665 10704 11273 11333>, + <9653 9653 9663 10732 11295 11236>, + <9653 9653 9662 10795 11303 11164>, + <9653 9653 9661 10797 11232 11154>, + <9653 9653 9660 10768 11213 11165>, + <9652 9653 9659 10741 11214 11105>, + <9651 9653 9658 10661 11159 11059>, + <9650 9652 9657 10616 11088 11003>, + <9650 9651 9656 10566 10982 10904>, + <9648 9650 9655 10519 10871 10771>, + <9648 9650 9655 10519 10871 10771>, + <9648 9650 9655 10519 10871 10771>; + }; + + qcom,pc-temp-y3-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <14894 13675 13387 13307 13288 13282>, + <14761 13671 13390 13308 13286 13280>, + <14612 13660 13393 13309 13284 13279>, + <14466 13645 13396 13310 13283 13278>, + <14339 13628 13399 13311 13282 13278>, + <14251 13610 13402 13312 13282 13278>, + <14211 13592 13404 13313 13283 13278>, + <14196 13568 13406 13313 13284 13279>, + <14179 13541 13408 13314 13284 13279>, + <14129 13512 13411 13315 13283 13280>, + <14073 13500 13412 13316 13283 13280>, + <14057 13502 13412 13316 13285 13281>, + <14063 13505 13412 13317 13287 13281>, + <14032 13507 13410 13317 13288 13280>, + <13973 13505 13404 13318 13290 13280>, + <13957 13504 13396 13318 13290 13280>, + <13957 13504 13389 13319 13291 13282>, + <13959 13496 13381 13319 13291 13284>, + <13962 13479 13372 13318 13293 13287>, + <13967 13456 13362 13315 13295 13288>, + <13982 13429 13355 13311 13292 13285>, + <14014 13403 13350 13305 13285 13279>, + <14050 13387 13346 13301 13283 13277>, + <14095 13378 13340 13298 13282 13277>, + <14145 13378 13330 13297 13282 13277>, + <14193 13390 13318 13296 13281 13276>, + <14243 13411 13306 13296 13279 13276>, + <14295 13435 13293 13296 13279 13276>, + <14353 13462 13273 13296 13279 13276>, + <14413 13494 13260 13295 13280 13276>, + <14474 13533 13260 13295 13280 13275>, + <14537 13580 13261 13294 13281 13275>, + <14602 13634 13261 13294 13281 13276>, + <14670 13695 13261 13293 13282 13276>, + <14736 13767 13264 13293 13282 13276>, + <14799 13851 13282 13294 13280 13276>, + <14862 13945 13312 13294 13279 13275>, + <14926 14048 13331 13291 13279 13275>, + <14990 14162 13335 13284 13279 13275>, + <15053 14281 13336 13283 13278 13275>, + <15115 14406 13343 13290 13278 13275>, + <15180 14531 13361 13293 13278 13275>, + <15247 14652 13395 13294 13277 13275>, + <15325 14760 13446 13296 13277 13274>, + <15372 14809 13489 13296 13278 13275>, + <15544 14923 13525 13303 13280 13277>, + <15659 14973 13563 13309 13281 13280>, + <15786 14998 13617 13315 13286 13283>, + <15982 14992 13666 13319 13288 13283>, + <16341 15053 13698 13323 13286 13281>, + <16796 15132 13761 13324 13287 13281>, + <17451 15263 13864 13331 13289 13283>, + <18369 15740 13993 13343 13291 13285>, + <19582 16580 14194 13360 13296 13288>, + <19582 16580 14194 13360 13296 13288>, + <19582 16580 14194 13360 13296 13288>; + }; + + qcom,pc-temp-y4-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <17253 17133 16743 16577 16480 16460>, + <17386 17231 16792 16587 16483 16461>, + <17568 17323 16861 16596 16486 16461>, + <17760 17403 16932 16602 16488 16461>, + <17920 17464 16989 16607 16489 16461>, + <18007 17499 17012 16608 16489 16461>, + <18009 17502 17012 16606 16488 16461>, + <17988 17500 17010 16602 16487 16462>, + <17999 17543 17006 16600 16488 16463>, + <18041 17680 16996 16599 16491 16465>, + <17967 17812 16989 16599 16494 16467>, + <17844 17840 17026 16601 16497 16469>, + <17736 17724 17085 16607 16500 16472>, + <17602 17539 17128 16618 16505 16479>, + <17436 17339 17166 16635 16511 16487>, + <17320 17297 17151 16652 16520 16495>, + <17244 17301 17110 16668 16534 16503>, + <17191 17252 17064 16689 16553 16515>, + <17124 17151 17004 16737 16591 16542>, + <17061 17040 16905 16780 16622 16564>, + <17025 16955 16810 16741 16596 16545>, + <17000 16890 16734 16612 16522 16494>, + <16985 16845 16684 16548 16487 16471>, + <16978 16817 16665 16531 16476 16462>, + <16977 16803 16663 16522 16471 16460>, + <16983 16798 16662 16519 16472 16460>, + <16991 16794 16658 16518 16474 16461>, + <17001 16792 16662 16518 16477 16464>, + <17010 16794 16686 16521 16481 16468>, + <17020 16799 16701 16525 16486 16473>, + <17027 16808 16700 16529 16495 16481>, + <17033 16819 16703 16532 16507 16490>, + <17039 16831 16711 16532 16521 16502>, + <17046 16844 16721 16528 16536 16513>, + <17054 16856 16725 16523 16536 16511>, + <17064 16874 16716 16507 16502 16483>, + <17071 16892 16701 16493 16470 16463>, + <17073 16896 16700 16494 16460 16460>, + <17074 16895 16718 16497 16455 16458>, + <17078 16898 16740 16501 16456 16458>, + <17086 16907 16756 16509 16461 16460>, + <17100 16916 16766 16520 16461 16457>, + <17127 16927 16777 16533 16464 16458>, + <17151 16945 16788 16535 16451 16440>, + <17171 16968 16822 16535 16453 16444>, + <17277 17044 16856 16576 16475 16464>, + <17341 17101 16922 16610 16490 16483>, + <17410 17129 16953 16651 16514 16518>, + <17486 17107 17015 16692 16536 16519>, + <17605 17116 17023 16691 16503 16472>, + <17753 17101 17030 16669 16495 16475>, + <17998 17092 17063 16706 16514 16494>, + <18444 17292 17132 16776 16554 16536>, + <19473 17868 17327 16903 16672 16712>, + <19473 17868 17327 16903 16672 16712>, + <19473 17868 17327 16903 16672 16712>; + }; + + qcom,pc-temp-y5-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <10911 10298 14213 16701 17755 21052>, + <10898 10547 14445 16766 17305 19443>, + <10949 10923 14667 16781 16536 18148>, + <11030 11360 14873 16758 15705 17155>, + <11105 11790 15060 16708 15066 16451>, + <11140 12156 15225 16638 14868 16040>, + <11427 12622 15397 16476 14926 16016>, + <12770 12870 15521 16320 14987 16092>, + <13889 12496 15526 16267 14730 15883>, + <13648 12382 15474 16192 14147 15511>, + <12823 13043 15351 16067 14037 15384>, + <13350 13999 14703 15767 14366 15172>, + <14369 14322 14084 15374 14619 14868>, + <13835 13655 14198 14817 14642 14286>, + <12387 13207 14689 14237 14597 13690>, + <11862 13518 15158 14092 14432 13665>, + <11843 14013 15618 14088 14125 13889>, + <11872 14061 16032 14147 14029 14160>, + <11697 13724 16290 14567 14307 14509>, + <11496 13360 16491 15286 14746 14893>, + <11296 12874 16629 16221 15422 15320>, + <11018 12157 16685 17422 16386 15876>, + <10915 11509 16661 17766 16912 16362>, + <10937 11055 16364 17245 17282 17294>, + <10949 10862 15125 16788 17482 17704>, + <10928 10863 14139 16796 17047 17507>, + <10893 10892 13688 16847 16257 17185>, + <10862 10972 13103 16906 15960 16859>, + <10846 11049 11861 16955 16035 16391>, + <10863 11085 11085 16970 16245 16032>, + <10920 11156 11094 16960 16494 15813>, + <11002 11238 11065 16985 16807 15733>, + <11078 11244 11007 17138 17386 15954>, + <11131 11221 10960 17460 18188 16486>, + <11133 11274 11023 17775 18436 17083>, + <11097 11459 11423 18423 18423 17731>, + <11069 11605 11910 18965 18423 18211>, + <11060 11618 12071 17553 19122 18678>, + <11055 11604 12039 14324 19839 19105>, + <11037 11603 11978 13643 19020 19029>, + <11002 11612 11919 15021 17826 18387>, + <10971 11599 11823 15233 17990 17895>, + <10972 11465 11745 14656 16514 17780>, + <11158 11428 11876 14911 18206 19748>, + <11212 11498 11959 14662 17928 18323>, + <11369 11538 11852 15035 16485 16557>, + <11571 11627 12089 15093 15314 16819>, + <11625 11902 12653 15141 16476 16374>, + <11579 12519 13295 14848 16431 16247>, + <11380 12618 13272 15759 17268 17871>, + <11028 12392 13194 15990 18549 17841>, + <10501 11978 13207 15787 18547 18581>, + <10084 11290 12982 15884 18113 18317>, + <9775 10649 12845 16062 18034 18316>, + <9775 10649 12845 16062 18034 18316>, + <9775 10649 12845 16062 18034 18316>; + }; + + qcom,pc-temp-y6-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <7509 6257 5552 5162 5046 5022>, + <7463 6254 5559 5162 5046 5021>, + <7413 6247 5566 5163 5045 5020>, + <7363 6237 5570 5163 5044 5019>, + <7317 6225 5572 5162 5044 5018>, + <7278 6214 5572 5162 5043 5018>, + <7243 6201 5566 5160 5043 5018>, + <7222 6185 5556 5157 5042 5019>, + <7224 6169 5548 5155 5042 5019>, + <7201 6173 5539 5153 5042 5020>, + <7139 6196 5532 5152 5042 5020>, + <7087 6209 5536 5152 5044 5021>, + <7056 6178 5547 5152 5046 5022>, + <6999 6115 5554 5154 5048 5024>, + <6917 6048 5556 5158 5050 5025>, + <6873 6034 5546 5163 5053 5028>, + <6851 6036 5529 5167 5057 5031>, + <6842 6018 5510 5173 5063 5036>, + <6825 5983 5485 5185 5075 5045>, + <6811 5944 5450 5195 5085 5053>, + <6818 5914 5419 5182 5075 5045>, + <6840 5894 5395 5141 5049 5026>, + <6866 5889 5380 5120 5037 5018>, + <6900 5891 5370 5113 5033 5015>, + <6939 5897 5361 5110 5032 5014>, + <6977 5914 5357 5110 5032 5014>, + <7015 5942 5356 5110 5032 5015>, + <7055 5972 5354 5110 5032 5015>, + <7098 6006 5353 5112 5034 5016>, + <7142 6046 5355 5114 5036 5018>, + <7189 6091 5362 5117 5039 5020>, + <7238 6142 5372 5119 5043 5023>, + <7287 6197 5384 5120 5048 5027>, + <7337 6258 5398 5120 5054 5031>, + <7385 6325 5416 5120 5054 5030>, + <7432 6399 5439 5119 5044 5022>, + <7479 6479 5466 5117 5034 5017>, + <7525 6560 5497 5117 5032 5016>, + <7573 6645 5535 5117 5031 5016>, + <7622 6734 5578 5119 5031 5016>, + <7671 6829 5627 5130 5033 5017>, + <7725 6923 5681 5142 5034 5016>, + <7782 7014 5743 5151 5035 5017>, + <7845 7098 5815 5160 5032 5012>, + <7891 7143 5876 5164 5035 5014>, + <8048 7251 5926 5190 5043 5022>, + <8152 7306 5983 5210 5048 5029>, + <8272 7333 6038 5233 5060 5042>, + <8457 7327 6100 5254 5067 5042>, + <8797 7374 6135 5262 5057 5027>, + <9221 7430 6200 5263 5056 5028>, + <9832 7529 6307 5294 5065 5036>, + <10714 7994 6439 5339 5079 5051>, + <11882 8845 6653 5404 5118 5105>, + <11882 8845 6653 5404 5118 5105>, + <11882 8845 6653 5404 5118 5105>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi b/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi index c8338db24a595b8a4a33be2f824d1771a072f4a7..86354035b0e604c4f71d8d29efbe65b320033a9d 100644 --- a/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi @@ -9,13 +9,117 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +#include +#include + + +&qupv3_se6_spi { + status = "ok"; + can-controller@0 { + compatible = "qcom,nxp,mpc5746c"; + reg = <0>; + interrupt-parent = <&tlmm>; + interrupts = <40 0>; + spi-max-frequency = <5000000>; + qcom,clk-freq-mhz = <40000000>; + qcom,max-can-channels = <1>; + qcom,bits-per-word = <8>; + qcom,support-can-fd; + }; +}; &soc { + qcom,lpass@62400000 { + status = "ok"; + }; + + audio_apr: qcom,msm-audio-apr { + status = "ok"; + }; + qcom,glink { modem { status = "disabled"; }; }; + emac_hw: qcom,emac@20000 { + compatible = "qcom,emac-dwc-eqos"; + qcom,arm-smmu; + reg = <0x20000 0x10000>, + <0x36000 0x100>; + reg-names = "emac-base", "rgmii-base"; + dma-bit-mask = <32>; + emac-core-version = <7>; + interrupts-extended = <&pdc 0 660 4>, <&pdc 0 661 4>, + <&tlmm 121 2>, <&pdc 0 651 4>, + <&pdc 0 652 4>, <&pdc 0 653 4>, + <&pdc 0 654 4>, <&pdc 0 655 4>, + <&pdc 0 656 4>, <&pdc 0 657 4>, + <&pdc 0 658 4>, <&pdc 0 659 4>, + <&pdc 0 668 4>, <&pdc 0 669 4>; + interrupt-names = "sbd-intr", "lpi-intr", + "phy-intr", "tx-ch0-intr", + "tx-ch1-intr", "tx-ch2-intr", + "tx-ch3-intr", "tx-ch4-intr", + "rx-ch0-intr", "rx-ch1-intr", + "rx-ch2-intr", "rx-ch3-intr", + "ptp_pps_irq_0","ptp_pps_irq_1"; + qcom,msm-bus,name = "emac"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <98 512 0 0>, <1 781 0 0>, /* No vote */ + <98 512 1250 0>, <1 781 0 40000>, /* 10Mbps vote */ + <98 512 12500 0>, <1 781 0 40000>, /* 100Mbps vote */ + <98 512 125000 0>, <1 781 0 40000>; /* 1000Mbps vote */ + qcom,bus-vector-names = "0", "10", "100", "1000"; + clocks = <&clock_gcc GCC_EMAC_AXI_CLK>, + <&clock_gcc GCC_EMAC_PTP_CLK>, + <&clock_gcc GCC_EMAC_RGMII_CLK>, + <&clock_gcc GCC_EMAC_SLV_AHB_CLK>; + clock-names = "eth_axi_clk", "eth_ptp_clk", + "eth_rgmii_clk", "eth_slave_ahb_clk"; + qcom,phy-reset = <&tlmm 104 GPIO_ACTIVE_HIGH>; + qcom,phy-intr-redirect = <&tlmm 121 GPIO_ACTIVE_LOW>; + gdsc_emac-supply = <&emac_gdsc>; + pinctrl-names = "dev-emac-mdc", "dev-emac-mdio", + "dev-emac-rgmii_txd0_state", "dev-emac-rgmii_txd1_state", + "dev-emac-rgmii_txd2_state", "dev-emac-rgmii_txd3_state", + "dev-emac-rgmii_txc_state", "dev-emac-rgmii_tx_ctl_state", + "dev-emac-rgmii_rxd0_state", "dev-emac-rgmii_rxd1_state", + "dev-emac-rgmii_rxd2_state", "dev-emac-rgmii_rxd3_state", + "dev-emac-rgmii_rxc_state", "dev-emac-rgmii_rx_ctl_state", + "dev-emac-phy_intr", "dev-emac-phy_reset_state", + "dev-emac_pin_pps_0"; + + pinctrl-0 = <&emac_mdc>; + pinctrl-1 = <&emac_mdio>; + pinctrl-2 = <&emac_rgmii_txd0>; + pinctrl-3 = <&emac_rgmii_txd1>; + pinctrl-4 = <&emac_rgmii_txd2>; + pinctrl-5 = <&emac_rgmii_txd3>; + pinctrl-6 = <&emac_rgmii_txc>; + pinctrl-7 = <&emac_rgmii_tx_ctl>; + pinctrl-8 = <&emac_rgmii_rxd0>; + pinctrl-9 = <&emac_rgmii_rxd1>; + pinctrl-10 = <&emac_rgmii_rxd2>; + pinctrl-11 = <&emac_rgmii_rxd3>; + pinctrl-12 = <&emac_rgmii_rxc>; + pinctrl-13 = <&emac_rgmii_rx_ctl>; + pinctrl-14 = <&emac_phy_intr>; + pinctrl-15 = <&emac_phy_reset_state>; + pinctrl-16 = <&emac_pin_pps_0>; + + io-macro-info { + io-macro-bypass-mode = <0>; + io-interface = "rgmii"; + }; + emac_emb_smmu: emac_emb_smmu { + compatible = "qcom,emac-smmu-embedded"; + iommus = <&apps_smmu 0x1C0 0x0>; + qcom,iova-mapping = <0x80000000 0x40000000>; + }; + }; }; &ufsphy_mem { @@ -82,10 +186,9 @@ status = "ok"; }; -&usb0 { - dwc3@a600000 { - dr_mode = "peripheral"; - }; +&usb1 { + status = "ok"; + qcom,default-mode-host; }; &qupv3_se0_2uart { diff --git a/arch/arm64/boot/dts/qcom/sa6155-audio.dtsi b/arch/arm64/boot/dts/qcom/sa6155-audio.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..4f08d6acbdaee27acd9fc710e3a90b920914dd06 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa6155-audio.dtsi @@ -0,0 +1,505 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + qcom,msm-dai-tdm-pri-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37120>; + qcom,msm-cpudai-tdm-group-num-ports = <4>; + qcom,msm-cpudai-tdm-group-port-id = <36864 36866 36868 36870>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; + dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36864>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_pri_tdm_rx_1: qcom,msm-dai-q6-tdm-pri-rx-1 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36866>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_pri_tdm_rx_2: qcom,msm-dai-q6-tdm-pri-rx-2 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36868>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_pri_tdm_rx_3: qcom,msm-dai-q6-tdm-pri-rx-3 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36870>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-pri-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37121>; + qcom,msm-cpudai-tdm-group-num-ports = <4>; + qcom,msm-cpudai-tdm-group-port-id = <36865 36867 36869 36871>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; + dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36865>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_pri_tdm_tx_1: qcom,msm-dai-q6-tdm-pri-tx-1 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36867>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_pri_tdm_tx_2: qcom,msm-dai-q6-tdm-pri-tx-2 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36869>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_pri_tdm_tx_3: qcom,msm-dai-q6-tdm-pri-tx-3 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36871>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-sec-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37136>; + qcom,msm-cpudai-tdm-group-num-ports = <4>; + qcom,msm-cpudai-tdm-group-port-id = <36880 36882 36884 36886>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; + dai_sec_tdm_rx_0: qcom,msm-dai-q6-tdm-sec-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36880>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_sec_tdm_rx_1: qcom,msm-dai-q6-tdm-sec-rx-1 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36882>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_sec_tdm_rx_2: qcom,msm-dai-q6-tdm-sec-rx-2 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36884>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_sec_tdm_rx_3: qcom,msm-dai-q6-tdm-sec-rx-3 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36886>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-sec-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37137>; + qcom,msm-cpudai-tdm-group-num-ports = <4>; + qcom,msm-cpudai-tdm-group-port-id = <36881 36883 36885 36887>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; + dai_sec_tdm_tx_0: qcom,msm-dai-q6-tdm-sec-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36881>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_sec_tdm_tx_1: qcom,msm-dai-q6-tdm-sec-tx-1 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36883>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_sec_tdm_tx_2: qcom,msm-dai-q6-tdm-sec-tx-2 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36885>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_sec_tdm_tx_3: qcom,msm-dai-q6-tdm-sec-tx-3 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36887>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-tert-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37152>; + qcom,msm-cpudai-tdm-group-num-ports = <5>; + qcom,msm-cpudai-tdm-group-port-id = <36896 36898 36900 + 36902 36904>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; + dai_tert_tdm_rx_0: qcom,msm-dai-q6-tdm-tert-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36896>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_tert_tdm_rx_1: qcom,msm-dai-q6-tdm-tert-rx-1 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36898>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_tert_tdm_rx_2: qcom,msm-dai-q6-tdm-tert-rx-2 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36900>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_tert_tdm_rx_3: qcom,msm-dai-q6-tdm-tert-rx-3 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36902>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_tert_tdm_rx_4: qcom,msm-dai-q6-tdm-tert-rx-4 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36904>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-tert-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37153>; + qcom,msm-cpudai-tdm-group-num-ports = <4>; + qcom,msm-cpudai-tdm-group-port-id = <36897 36899 36901 36903>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; + dai_tert_tdm_tx_0: qcom,msm-dai-q6-tdm-tert-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36897>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_tert_tdm_tx_1: qcom,msm-dai-q6-tdm-tert-tx-1 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36899>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_tert_tdm_tx_2: qcom,msm-dai-q6-tdm-tert-tx-2 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36901>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_tert_tdm_tx_3: qcom,msm-dai-q6-tdm-tert-tx-3 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36903>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-quat-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37168>; + qcom,msm-cpudai-tdm-group-num-ports = <4>; + qcom,msm-cpudai-tdm-group-port-id = <36912 36914 36916 36918>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; + dai_quat_tdm_rx_0: qcom,msm-dai-q6-tdm-quat-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36912>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_quat_tdm_rx_1: qcom,msm-dai-q6-tdm-quat-rx-1 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36914>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_quat_tdm_rx_2: qcom,msm-dai-q6-tdm-quat-rx-2 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36916>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_quat_tdm_rx_3: qcom,msm-dai-q6-tdm-quat-rx-3 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36918>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-quat-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37169>; + qcom,msm-cpudai-tdm-group-num-ports = <4>; + qcom,msm-cpudai-tdm-group-port-id = <36913 36915 36917 36919>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; + dai_quat_tdm_tx_0: qcom,msm-dai-q6-tdm-quat-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36913>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_quat_tdm_tx_1: qcom,msm-dai-q6-tdm-quat-tx-1 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36915>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_quat_tdm_tx_2: qcom,msm-dai-q6-tdm-quat-tx-2 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36917>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_quat_tdm_tx_3: qcom,msm-dai-q6-tdm-quat-tx-3 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36919>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-quin-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37184>; + qcom,msm-cpudai-tdm-group-num-ports = <4>; + qcom,msm-cpudai-tdm-group-port-id = <36928 36930 36932 36934>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; + dai_quin_tdm_rx_0: qcom,msm-dai-q6-tdm-quin-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36928>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_quin_tdm_rx_1: qcom,msm-dai-q6-tdm-quin-rx-1 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36930>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_quin_tdm_rx_2: qcom,msm-dai-q6-tdm-quin-rx-2 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36932>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_quin_tdm_rx_3: qcom,msm-dai-q6-tdm-quin-rx-3 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36934>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-quin-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37185>; + qcom,msm-cpudai-tdm-group-num-ports = <4>; + qcom,msm-cpudai-tdm-group-port-id = <36929 36931 36933 36935>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; + dai_quin_tdm_tx_0: qcom,msm-dai-q6-tdm-quin-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36929>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_quin_tdm_tx_1: qcom,msm-dai-q6-tdm-quin-tx-1 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36931>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_quin_tdm_tx_2: qcom,msm-dai-q6-tdm-quin-tx-2 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36933>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + + dai_quin_tdm_tx_3: qcom,msm-dai-q6-tdm-quin-tx-3 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36935>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; +}; + +&audio_apr { + status = "ok"; + q6core: qcom,q6core-audio { + status = "disabled"; + sm6150_snd: sound { + status = "disabled"; + }; + bolero: bolero-cdc { + status = "disabled"; + }; + }; + + sound-adp-star { + status = "ok"; + compatible = "qcom,sa8155-asoc-snd-adp-star"; + qcom,model = "sa8155-adp-star-snd-card"; + qcom,mi2s-audio-intf; + qcom,auxpcm-audio-intf; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>; + + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&compr>, + <&pcm_noirq>, <&loopback1>, <&pcm_dtmf>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-compr-dsp", + "msm-pcm-dsp-noirq", "msm-pcm-loopback.1", + "msm-pcm-dtmf"; + asoc-cpu = <&dai_hdmi>, <&dai_dp>, + <&dai_mi2s0>, <&dai_mi2s1>, + <&dai_mi2s2>, <&dai_mi2s3>, + <&dai_mi2s4>, <&dai_pri_auxpcm>, + <&dai_sec_auxpcm>, <&dai_tert_auxpcm>, + <&dai_quat_auxpcm>, <&dai_quin_auxpcm>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, + <&usb_audio_rx>, <&usb_audio_tx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_rx_1>, + <&dai_pri_tdm_rx_2>, <&dai_pri_tdm_rx_3>, + <&dai_pri_tdm_tx_0>, <&dai_pri_tdm_tx_1>, + <&dai_pri_tdm_tx_2>, <&dai_pri_tdm_tx_3>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_rx_1>, + <&dai_sec_tdm_rx_2>, <&dai_sec_tdm_rx_3>, + <&dai_sec_tdm_tx_0>, <&dai_sec_tdm_tx_1>, + <&dai_sec_tdm_tx_2>, <&dai_sec_tdm_tx_3>, + <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>, + <&dai_tert_tdm_rx_2>, <&dai_tert_tdm_rx_3>, + <&dai_tert_tdm_rx_4>, <&dai_tert_tdm_tx_0>, + <&dai_tert_tdm_tx_1>, <&dai_tert_tdm_tx_2>, + <&dai_tert_tdm_tx_3>, <&dai_quat_tdm_rx_0>, + <&dai_quat_tdm_rx_1>, <&dai_quat_tdm_rx_2>, + <&dai_quat_tdm_rx_3>, <&dai_quat_tdm_tx_0>, + <&dai_quat_tdm_tx_1>, <&dai_quat_tdm_tx_2>, + <&dai_quat_tdm_tx_3>, <&dai_quin_tdm_rx_0>, + <&dai_quin_tdm_rx_1>, <&dai_quin_tdm_rx_2>, + <&dai_quin_tdm_rx_3>, <&dai_quin_tdm_tx_0>, + <&dai_quin_tdm_tx_1>, <&dai_quin_tdm_tx_2>, + <&dai_quin_tdm_tx_3>; + asoc-cpu-names = "msm-dai-q6-hdmi.8", "msm-dai-q6-dp.24608", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-mi2s.4", "msm-dai-q6-auxpcm.1", + "msm-dai-q6-auxpcm.2", "msm-dai-q6-auxpcm.3", + "msm-dai-q6-auxpcm.4", "msm-dai-q6-auxpcm.5", + "msm-dai-q6-dev.224", "msm-dai-q6-dev.225", + "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", + "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", + "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", + "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36866", + "msm-dai-q6-tdm.36868", "msm-dai-q6-tdm.36870", + "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36867", + "msm-dai-q6-tdm.36869", "msm-dai-q6-tdm.36871", + "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36882", + "msm-dai-q6-tdm.36884", "msm-dai-q6-tdm.36886", + "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36883", + "msm-dai-q6-tdm.36885", "msm-dai-q6-tdm.36887", + "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898", + "msm-dai-q6-tdm.36900", "msm-dai-q6-tdm.36902", + "msm-dai-q6-tdm.36904", "msm-dai-q6-tdm.36897", + "msm-dai-q6-tdm.36899", "msm-dai-q6-tdm.36901", + "msm-dai-q6-tdm.36903", "msm-dai-q6-tdm.36912", + "msm-dai-q6-tdm.36914", "msm-dai-q6-tdm.36916", + "msm-dai-q6-tdm.36918", "msm-dai-q6-tdm.36913", + "msm-dai-q6-tdm.36915", "msm-dai-q6-tdm.36917", + "msm-dai-q6-tdm.36919", "msm-dai-q6-tdm.36928", + "msm-dai-q6-tdm.36930", "msm-dai-q6-tdm.36932", + "msm-dai-q6-tdm.36934", "msm-dai-q6-tdm.36929", + "msm-dai-q6-tdm.36931", "msm-dai-q6-tdm.36933", + "msm-dai-q6-tdm.36935"; + asoc-codec = <&stub_codec>; + asoc-codec-names = "msm-stub-codec.1"; + }; +}; + +&qupv3_se4_i2c { + status = "disabled"; +}; + +&slim_aud { + status = "disabled"; + msm_dai_slim { + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sa6155-pcie.dtsi b/arch/arm64/boot/dts/qcom/sa6155-pcie.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..44f9a761dfcfca2d999ca717f7e98617854dc47a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa6155-pcie.dtsi @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +&soc { + pcie0: qcom,pcie@1c08000 { + compatible = "qcom,pci-msm"; + cell-index = <0>; + + reg = <0x1c08000 0x4000>, + <0x1c0e000 0x1000>, + <0x40000000 0xf1d>, + <0x40000f20 0xa8>, + <0x40001000 0x1000>, + <0x40100000 0x100000>, + <0x40200000 0x100000>, + <0x40300000 0x1fd00000>; + + reg-names = "parf", "phy", "dm_core", "elbi", + "iatu", "conf", "io", "bars"; + + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x01000000 0x0 0x40200000 0x40200000 0x0 0x100000>, + <0x02000000 0x0 0x40300000 0x40300000 0x0 0x1fd00000>; + interrupt-parent = <&pcie0>; + interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 + 36 37>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0xffffffff>; + interrupt-map = <0 0 0 0 &intc 0 141 0 + 0 0 0 1 &intc 0 149 0 + 0 0 0 2 &intc 0 150 0 + 0 0 0 3 &intc 0 151 0 + 0 0 0 4 &intc 0 152 0 + 0 0 0 5 &intc 0 140 0 + 0 0 0 6 &intc 0 768 0 + 0 0 0 7 &intc 0 769 0 + 0 0 0 8 &intc 0 770 0 + 0 0 0 9 &intc 0 771 0 + 0 0 0 10 &intc 0 772 0 + 0 0 0 11 &intc 0 773 0 + 0 0 0 12 &intc 0 774 0 + 0 0 0 13 &intc 0 775 0 + 0 0 0 14 &intc 0 776 0 + 0 0 0 15 &intc 0 777 0 + 0 0 0 16 &intc 0 778 0 + 0 0 0 17 &intc 0 779 0 + 0 0 0 18 &intc 0 780 0 + 0 0 0 19 &intc 0 781 0 + 0 0 0 20 &intc 0 782 0 + 0 0 0 21 &intc 0 783 0 + 0 0 0 22 &intc 0 784 0 + 0 0 0 23 &intc 0 785 0 + 0 0 0 24 &intc 0 786 0 + 0 0 0 25 &intc 0 787 0 + 0 0 0 26 &intc 0 788 0 + 0 0 0 27 &intc 0 789 0 + 0 0 0 28 &intc 0 790 0 + 0 0 0 29 &intc 0 791 0 + 0 0 0 30 &intc 0 792 0 + 0 0 0 31 &intc 0 793 0 + 0 0 0 32 &intc 0 794 0 + 0 0 0 33 &intc 0 795 0 + 0 0 0 34 &intc 0 796 0 + 0 0 0 35 &intc 0 797 0 + 0 0 0 36 &intc 0 798 0 + 0 0 0 37 &intc 0 799 0>; + + interrupt-names = "int_msi", "int_a", "int_b", "int_c", + "int_d", "int_global_int", + "msi_0", "msi_1", "msi_2", "msi_3", + "msi_4", "msi_5", "msi_6", "msi_7", + "msi_8", "msi_9", "msi_10", "msi_11", + "msi_12", "msi_13", "msi_14", "msi_15", + "msi_16", "msi_17", "msi_18", "msi_19", + "msi_20", "msi_21", "msi_22", "msi_23", + "msi_24", "msi_25", "msi_26", "msi_27", + "msi_28", "msi_29", "msi_30", "msi_31"; + + qcom,phy-sequence = <0x0800 0x01 0x0 + 0x0804 0x03 0x0 + 0x0034 0x18 0x0 + 0x0038 0x10 0x0 + 0x0294 0x06 0x0 + 0x00c8 0x01 0x0 + 0x0128 0x00 0x0 + 0x0144 0xff 0x0 + 0x0148 0x1f 0x0 + 0x0070 0x0f 0x0 + 0x0048 0x0f 0x0 + 0x0178 0x00 0x0 + 0x019c 0x01 0x0 + 0x018c 0x20 0x0 + 0x0184 0x0a 0x0 + 0x00b4 0x20 0x0 + 0x000c 0x09 0x0 + 0x00ac 0x04 0x0 + 0x00d0 0x82 0x0 + 0x00e4 0x03 0x0 + 0x00e0 0x55 0x0 + 0x00dc 0x55 0x0 + 0x0054 0x00 0x0 + 0x0050 0x0d 0x0 + 0x004c 0x04 0x0 + 0x0174 0x33 0x0 + 0x003c 0x02 0x0 + 0x0040 0x1f 0x0 + 0x0078 0x0b 0x0 + 0x0084 0x16 0x0 + 0x0090 0x28 0x0 + 0x010c 0x00 0x0 + 0x0108 0x80 0x0 + 0x0010 0x01 0x0 + 0x001c 0x31 0x0 + 0x0020 0x01 0x0 + 0x0014 0x02 0x0 + 0x0018 0x00 0x0 + 0x0024 0x2f 0x0 + 0x0028 0x19 0x0 + 0x0268 0x45 0x0 + 0x0194 0x06 0x0 + 0x024c 0x02 0x0 + 0x02ac 0x12 0x0 + 0x0510 0x1c 0x0 + 0x051c 0x14 0x0 + 0x04d8 0x01 0x0 + 0x04dc 0x00 0x0 + 0x04e0 0xdb 0x0 + 0x0448 0x4b 0x0 + 0x041c 0x04 0x0 + 0x0410 0x04 0x0 + 0x0074 0x19 0x0 + 0x0854 0x04 0x0 + 0x09ac 0x00 0x0 + 0x08a0 0x40 0x0 + 0x09e0 0x00 0x0 + 0x09dc 0x40 0x0 + 0x09a8 0x00 0x0 + 0x08a4 0x40 0x0 + 0x08a8 0x73 0x0 + 0x0518 0x99 0x0 + 0x0824 0x15 0x0 + 0x0828 0x0e 0x0 + 0x09b0 0x07 0x0 + 0x0800 0x00 0x0 + 0x0808 0x03 0x0>; + + pinctrl-names = "default"; + pinctrl-0 = <&pcie0_clkreq_default + &pcie0_perst_default + &pcie0_wake_default>; + + perst-gpio = <&tlmm 101 0>; + wake-gpio = <&tlmm 100 0>; + + gdsc-vdd-supply = <&pcie_0_gdsc>; + vreg-1.8-supply = <&L12A>; + vreg-0.9-supply = <&L5A>; + + vreg-cx-supply = <&VDD_CX_LEVEL>; + + qcom,vreg-1.8-voltage-level = <1800000 1800000 24000>; + qcom,vreg-0.9-voltage-level = <925000 925000 24000>; + qcom,vreg-cx-voltage-level = ; + + qcom,no-l0s-supported; + + qcom,max-link-speed = <0x2>; + + qcom,ep-latency = <10>; + + qcom,slv-addr-space-size = <0x20000000>; + + qcom,phy-status-offset = <0x974>; + qcom,phy-power-down-offset = <0x804>; + + qcom,boot-option = <0x1>; + + linux,pci-domain = <0>; + + qcom,msi-gicm-addr = <0x17a00040>; + qcom,msi-gicm-base = <0x320>; + + qcom,pcie-phy-ver = <0x10>; + qcom,use-19p2mhz-aux-clk; + + qcom,msm-bus,name = "pcie0"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <45 512 0 0>, + <45 512 500 800>; + + clocks = <&clock_gcc GCC_PCIE_0_PIPE_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_PCIE_0_AUX_CLK>, + <&clock_gcc GCC_PCIE_0_CFG_AHB_CLK>, + <&clock_gcc GCC_PCIE_0_MSTR_AXI_CLK>, + <&clock_gcc GCC_PCIE_0_SLV_AXI_CLK>, + <&clock_gcc GCC_PCIE_0_CLKREF_CLK>, + <&clock_gcc GCC_PCIE_0_SLV_Q2A_AXI_CLK>, + <&clock_gcc GCC_PCIE0_PHY_REFGEN_CLK>, + <&clock_gcc GCC_PCIE_PHY_AUX_CLK>; + + clock-names = "pcie_0_pipe_clk", "pcie_0_ref_clk_src", + "pcie_0_aux_clk", "pcie_0_cfg_ahb_clk", + "pcie_0_mstr_axi_clk", "pcie_0_slv_axi_clk", + "pcie_0_ldo", "pcie_0_slv_q2a_axi_clk", + "pcie_phy_refgen_clk", "pcie_phy_aux_clk"; + + max-clock-frequency-hz = <0>, <0>, <19200000>, <0>, <0>, <0>, + <0>, <0>, <0>, <0>, <100000000>, <0>; + + resets = <&clock_gcc GCC_PCIE_0_BCR>, + <&clock_gcc GCC_PCIE_0_PHY_BCR>; + + reset-names = "pcie_0_core_reset", + "pcie_0_phy_reset"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sa6155.dtsi b/arch/arm64/boot/dts/qcom/sa6155.dtsi index 10d67f890e5c8f7307bfc9c9d4b00d5a9e494226..f9135335e30db4a5a37e3395d38f89d4a2bdae35 100644 --- a/arch/arm64/boot/dts/qcom/sa6155.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155.dtsi @@ -19,6 +19,10 @@ compatible = "qcom,sa6155"; qcom,msm-name = "SA6155"; qcom,msm-id = <384 0x10000>; + + aliases { + pci-domain0 = &pcie0; /* PCIe0 domain */ + }; }; &qusb_phy0 { @@ -232,3 +236,4 @@ &mdss_mdp { connectors = <&sde_rscc &dsi_dp1 &sde_wb>; }; +#include "sa6155-pcie.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sa6155p-adp-star-overlay.dts b/arch/arm64/boot/dts/qcom/sa6155p-adp-star-overlay.dts index ba038632f1e8dc62efa89ba139748a822a23aee1..c892af7c15c32a767425a15ab99b660c3b1d835a 100644 --- a/arch/arm64/boot/dts/qcom/sa6155p-adp-star-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sa6155p-adp-star-overlay.dts @@ -14,6 +14,7 @@ /plugin/; #include +#include #include "sa6155-adp-star.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sa6155p.dtsi b/arch/arm64/boot/dts/qcom/sa6155p.dtsi index 9a7e73efaaefd3febdc0d0581441a4a7705380ca..ac7414621a6ac33a3ac3bb3f48d21222befb23b9 100644 --- a/arch/arm64/boot/dts/qcom/sa6155p.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155p.dtsi @@ -14,10 +14,15 @@ #include "sa6155-pmic.dtsi" #include +#include "sm6150-camera-sensor-adp.dtsi" / { model = "Qualcomm Technologies, Inc. SA6155P"; qcom,msm-name = "SA6155P"; qcom,msm-id = <377 0>; + + aliases { + pci-domain0 = &pcie0; /* PCIe0 domain */ + }; }; /* Delete second instance of pm6155 definitions for APQ version */ @@ -253,3 +258,7 @@ &mdss_mdp { connectors = <&sde_rscc &dsi_dp1 &sde_wb>; }; + +/* Audio device tree */ +#include "sa6155-audio.dtsi" +#include "sa6155-pcie.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sa8155-adp-star-overlay.dts b/arch/arm64/boot/dts/qcom/sa8155-adp-star-overlay.dts index 611d29151e3777385286e9eb8188c4c176acfa2b..4dd522713b208e94605e1e694da277dd44285f4f 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-adp-star-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sa8155-adp-star-overlay.dts @@ -13,6 +13,8 @@ /dts-v1/; /plugin/; +#include + #include "sa8155-adp-star.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/sa8155-adp-star.dtsi b/arch/arm64/boot/dts/qcom/sa8155-adp-star.dtsi index 69b5b38fb564b233bb5d1e2e8536f8e672613831..9ec9a6812cc5c9e207510bdc08d80af04a6cf7e0 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-adp-star.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-adp-star.dtsi @@ -14,6 +14,7 @@ #include #include "sa8155-pmic-overlay.dtsi" +#include "sm8150-camera-sensor-adp-star.dtsi" &qupv3_se0_spi { status = "ok"; diff --git a/arch/arm64/boot/dts/qcom/sa8155-regulator.dtsi b/arch/arm64/boot/dts/qcom/sa8155-regulator.dtsi index 16873c1c64c006c2e80963f5268b85bf66e9fa4b..c092d73c12de02eb33127a958d459b185b2affe4 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-regulator.dtsi @@ -49,7 +49,7 @@ regulator-name = "pm8150_1_s6"; qcom,set = ; regulator-min-microvolt = <600000>; - regulator-max-microvolt = <1128000>; + regulator-max-microvolt = <1352000>; qcom,init-voltage = <600000>; }; }; @@ -155,7 +155,7 @@ regulator-name = "pm8150_1_l5"; qcom,set = ; regulator-min-microvolt = <880000>; - regulator-max-microvolt = <880000>; + regulator-max-microvolt = <888000>; qcom,init-voltage = <880000>; qcom,init-mode = ; }; @@ -164,7 +164,7 @@ regulator-name = "pm8150_1_l5_ao"; qcom,set = ; regulator-min-microvolt = <880000>; - regulator-max-microvolt = <880000>; + regulator-max-microvolt = <888000>; qcom,init-voltage = <880000>; qcom,init-mode = ; }; @@ -173,7 +173,7 @@ regulator-name = "pm8150_1_l5_so"; qcom,set = ; regulator-min-microvolt = <880000>; - regulator-max-microvolt = <880000>; + regulator-max-microvolt = <888000>; qcom,init-voltage = <880000>; qcom,init-mode = ; qcom,init-enable = <0>; @@ -394,9 +394,9 @@ S4C: pm8150_2_s4: regulator-pm8150-2-s4 { regulator-name = "pm8150_2_s4"; qcom,set = ; - regulator-min-microvolt = <1200000>; + regulator-min-microvolt = <800000>; regulator-max-microvolt = <1400000>; - qcom,init-voltage = <1200000>; + qcom,init-voltage = <800000>; }; }; @@ -664,6 +664,25 @@ }; }; + rpmh-regulator-ldoc15 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoc15"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L15C: pm8150_2_l15: regulator-pm8150-2-l15 { + regulator-name = "pm8150_2_l15"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1904000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + rpmh-regulator-ldoc16 { compatible = "qcom,rpmh-vrm-regulator"; mboxes = <&apps_rsc 0>; diff --git a/arch/arm64/boot/dts/qcom/sa8155-v2-adp-air-overlay.dts b/arch/arm64/boot/dts/qcom/sa8155-v2-adp-air-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..267d6f7891d88b17913ad42426c6563311802198 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8155-v2-adp-air-overlay.dts @@ -0,0 +1,23 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include "sa8155-adp-star.dtsi" + +/ { + model = "ADP-AIR"; + compatible = "qcom,sa8155-v2-adp-air", "qcom,sa8155", + "qcom,adp-air"; + qcom,board-id = <0X01000019 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8155-v2-adp-air.dts b/arch/arm64/boot/dts/qcom/sa8155-v2-adp-air.dts new file mode 100644 index 0000000000000000000000000000000000000000..d95b90938884630270c3ad26d60857ffc3213eea --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8155-v2-adp-air.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sa8155-v2.dtsi" +#include "sa8155-adp-star.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA8155 V2 ADP AIR"; + compatible = "qcom,sa8155-v2-adp-air", "qcom,sa8155", "qcom,adp-air"; + qcom,board-id = <0x01000019 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8155.dtsi b/arch/arm64/boot/dts/qcom/sa8155.dtsi index c87d88e815dc31eb6ab62deaf6aee4e37b6eacfc..758cd4ed05cbee2d6b7c27d05a0ef6688260b946 100644 --- a/arch/arm64/boot/dts/qcom/sa8155.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155.dtsi @@ -753,3 +753,104 @@ }; #include "sa8155-audio.dtsi" + +/* GPU frequency overrides */ +&soc { + gpu_opp_table_v2: gpu_opp_table_v2 { + compatible = "operating-points-v2"; + + opp-700000000 { + opp-hz = /bits/ 64 <700000000>; + opp-microvolt = ; + }; + + opp-675000000 { + opp-hz = /bits/ 64 <675000000>; + opp-microvolt = ; + }; + + opp-585000000 { + opp-hz = /bits/ 64 <585000000>; + opp-microvolt = ; + }; + + opp-427000000 { + opp-hz = /bits/ 64 <427000000>; + opp-microvolt = ; + }; + + opp-345000000 { + opp-hz = /bits/ 64 <345000000>; + opp-microvolt = ; + }; + + opp-257000000 { + opp-hz = /bits/ 64 <257000000>; + opp-microvolt = ; + }; + + }; +}; + +/* GPU power level overrides */ +&msm_gpu { + qcom,gpu-pwrlevels { + compatible = "qcom,gpu-pwrlevels"; + + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <700000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <8>; + qcom,bus-max = <11>; + }; + + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <675000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <9>; + }; + + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <585000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <6>; + qcom,bus-max = <11>; + }; + + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <427000000>; + qcom,bus-freq = <6>; + qcom,bus-min = <5>; + qcom,bus-max = <9>; + }; + + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <345000000>; + qcom,bus-freq = <3>; + qcom,bus-min = <3>; + qcom,bus-max = <8>; + }; + + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <257000000>; + qcom,bus-freq = <2>; + qcom,bus-min = <1>; + qcom,bus-max = <8>; + }; + + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8155p-adp-star-overlay.dts b/arch/arm64/boot/dts/qcom/sa8155p-adp-star-overlay.dts index 298df1df8ad102bb57f18e4930c137032501b8ba..6c8c6688da1a511a4f3ea6291be5a5df90d5155e 100644 --- a/arch/arm64/boot/dts/qcom/sa8155p-adp-star-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sa8155p-adp-star-overlay.dts @@ -13,6 +13,8 @@ /dts-v1/; /plugin/; +#include + #include "sa8155-adp-star.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/sa8155p-v2-adp-air-overlay.dts b/arch/arm64/boot/dts/qcom/sa8155p-v2-adp-air-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..41a1132485de2da6b25e9856b80c269a76e1e5a4 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8155p-v2-adp-air-overlay.dts @@ -0,0 +1,23 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include "sa8155-adp-star.dtsi" + +/ { + model = "ADP-AIR"; + compatible = "qcom,sa8155p-v2-adp-air", "qcom,sa8155p", + "qcom,adp-air"; + qcom,board-id = <0x01000019 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sa8155p-v2-adp-air.dts b/arch/arm64/boot/dts/qcom/sa8155p-v2-adp-air.dts new file mode 100644 index 0000000000000000000000000000000000000000..8d270657542d1611aa48f7b1614c25f80d945870 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa8155p-v2-adp-air.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sa8155p-v2.dtsi" +#include "sa8155-adp-star.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA8155P V2 ADP AIR"; + compatible = "qcom,sa8155p-v2-adp-air", "qcom,sa8155p", "qcom,adp-air"; + qcom,board-id = <0x01000019 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-audio-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..8f519cd5eac1cd7367727d78de4fa79923090515 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-audio-overlay.dtsi @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "sm6150-audio-overlay.dtsi" + +&swr0 { + interrupts = <0 295 0>; +}; + +&swr1 { + interrupts = <0 297 0>; +}; + +&swr2 { + interrupts = <0 296 0>, <0 528 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-audio.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-audio.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ef1c61a7c73dfa62b35dd580a97e79d79425288b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-audio.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "sm6150-audio.dtsi" + +&msm_audio_ion { + iommus = <&apps_smmu 0x1b21 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-coresight.dtsi index d038729519519d3943b9057d7687365f4cd15762..d568730d5570e1084e3c37cc53ad79bb6ef38c06 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-coresight.dtsi @@ -110,7 +110,6 @@ <0x6064000 0x15000>; reg-names = "tmc-base", "bam-base"; - qcom,smmu-s1-bypass; iommus = <&apps_smmu 0x05e0 0>, <&apps_smmu 0x04a0 0>; @@ -1529,15 +1528,6 @@ }; port@8 { - reg = <9>; - tpda_in_tpdm_dcc: endpoint { - slave-mode; - remote-endpoint = - <&tpdm_dcc_out_tpda>; - }; - }; - - port@9 { reg = <10>; tpda_in_tpdm_prng: endpoint { slave-mode; @@ -1546,7 +1536,7 @@ }; }; - port@10 { + port@9 { reg = <11>; tpda_in_tpdm_north: endpoint { slave-mode; @@ -1555,7 +1545,7 @@ }; }; - port@11 { + port@10 { reg = <12>; tpda_in_tpdm_qm: endpoint { slave-mode; @@ -1564,7 +1554,7 @@ }; }; - port@12 { + port@11 { reg = <13>; tpda_in_tpdm_pimem: endpoint { slave-mode; @@ -1573,6 +1563,15 @@ }; }; + port@12 { + reg = <14>; + tpda_in_tpdm_npu: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_npu_out_tpda>; + }; + }; + port@13 { reg = <15>; tpda_in_tpdm_center: endpoint { @@ -1947,25 +1946,6 @@ }; }; - tpdm_dcc: tpdm@6870000 { - compatible = "arm,primecell"; - arm,primecell-periphid = <0x0003b968>; - reg = <0x6870000 0x1000>; - reg-names = "tpdm-base"; - - coresight-name = "coresight-tpdm-dcc"; - - clocks = <&clock_aop QDSS_CLK>; - clock-names = "apb_pclk"; - - - port { - tpdm_dcc_out_tpda: endpoint { - remote-endpoint = <&tpda_in_tpdm_dcc>; - }; - }; - }; - tpdm_prng: tpdm@684c000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b968>; @@ -2171,10 +2151,10 @@ clock-names = "apb_pclk"; }; - cti0_dlmm: cti@6c09000 { + cti0_dlmm: cti@69C1000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b966>; - reg = <0x6c09000 0x1000>; + reg = <0x69C1000 0x1000>; reg-names = "cti-base"; coresight-name = "coresight-cti-dlmm_cti0"; @@ -2183,10 +2163,10 @@ clock-names = "apb_pclk"; }; - cti1_dlmm: cti@6c0a000 { + cti1_dlmm: cti@69C2000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b966>; - reg = <0x6c0a000 0x1000>; + reg = <0x69C2000 0x1000>; reg-names = "cti-base"; coresight-name = "coresight-cti-dlmm_cti1"; @@ -2586,4 +2566,43 @@ clocks = <&clock_aop QDSS_CLK>; clock-names = "apb_pclk"; }; + + tpdm_npu: tpdm@69e1000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x69e1000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-npu"; + + clocks = <&clock_aop QDSS_CLK>, + <&clock_npucc NPU_CC_NPU_CORE_APB_CLK>, + <&clock_npucc NPU_CC_NPU_CORE_ATB_CLK>, + <&clock_npucc NPU_CC_NPU_CORE_CLK>, + <&clock_npucc NPU_CC_NPU_CORE_CLK_SRC>, + <&clock_npucc NPU_CC_NPU_CORE_CTI_CLK>; + + clock-names = "apb_pclk", + "npu_core_apb_clk", + "npu_core_atb_clk", + "npu_core_clk", + "npu_core_clk_src", + "npu_core_cti_clk"; + + qcom,tpdm-clks = "npu_core_apb_clk", + "npu_core_atb_clk", + "npu_core_clk", + "npu_core_clk_src", + "npu_core_cti_clk"; + + vdd-supply = <&npu_core_gdsc>; + vdd_cx-supply = <&VDD_CX_LEVEL>; + qcom,tpdm-regs = "vdd", "vdd_cx"; + + port{ + tpdm_npu_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_npu>; + }; + }; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-ext-codec-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-ext-codec-audio-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..31cb2e05670eb0783bf12b1996b01b89ff98f347 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-ext-codec-audio-overlay.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "sm6150-ext-codec-audio-overlay.dtsi" + +&wcd9xxx_intc { + qcom,gpio-connect = <&tlmm 58 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-external-codec-idp-overlay.dts b/arch/arm64/boot/dts/qcom/sdmmagpie-external-codec-idp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..1df5e2506c85f0157eb3e7eb09fdb3ae46f31792 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-external-codec-idp-overlay.dts @@ -0,0 +1,28 @@ + +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include + +#include "sdmmagpie-idp.dtsi" +#include "sdmmagpie-ext-codec-audio-overlay.dtsi" +#include "sdmmagpie-external-codec.dtsi" + +/ { + model = "External Audio Codec IDP"; + compatible = "qcom,sdmmagpie-idp", "qcom,sdmmagpie", "qcom,idp"; + qcom,msm-id = <365 0x0>; + qcom,board-id = <34 1>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-external-codec-idp.dts b/arch/arm64/boot/dts/qcom/sdmmagpie-external-codec-idp.dts new file mode 100644 index 0000000000000000000000000000000000000000..19ee94ec96ff9c080ecd8ca17cd410d2aa4e7947 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-external-codec-idp.dts @@ -0,0 +1,24 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sdmmagpie.dtsi" +#include "sdmmagpie-idp.dtsi" +#include "sdmmagpie-ext-codec-audio-overlay.dtsi" +#include "sdmmagpie-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDMMAGPIE PM6150 External Audio Codec IDP"; + compatible = "qcom,sdmmagpie-idp", "qcom,sdmmagpie", "qcom,idp"; + qcom,board-id = <34 1>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-external-codec.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-external-codec.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..36216dbfd3fb9ee1769ab14246d0cf75d47ff1ba --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-external-codec.dtsi @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "sm6150-external-codec.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-idp-overlay.dts b/arch/arm64/boot/dts/qcom/sdmmagpie-idp-overlay.dts index 8f04c8b58ba47fd7fc4089ea88c30b9b6590cf27..ec5e91ec0c33466e09ae0e5fe430a4139d8fc120 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie-idp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-idp-overlay.dts @@ -17,6 +17,7 @@ #include #include "sdmmagpie-idp.dtsi" +#include "sdmmagpie-audio-overlay.dtsi" / { model = "IDP"; @@ -24,3 +25,7 @@ qcom,msm-id = <365 0x0>; qcom,board-id = <34 0>; }; + +&dsi_sw43404_amoled_video_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-idp.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-idp.dtsi index 63596a831c738c5100cd9b3adae23cd2c00558ee..e15328c66a10fbfd9281f1b14dcb4fb5c382b341 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie-idp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-idp.dtsi @@ -12,6 +12,10 @@ #include "sdmmagpie-thermal-overlay.dtsi" #include +#include +#include +#include +#include "sdmmagpie-sde-display.dtsi" #include "sdmmagpie-camera-sensor-idp.dtsi" &soc { @@ -21,6 +25,10 @@ status = "ok"; }; +&qupv3_se3_4uart { + status = "ok"; +}; + &ufsphy_mem { compatible = "qcom,ufs-phy-qmp-v3"; @@ -82,3 +90,184 @@ status = "ok"; }; + +&dsi_sw43404_amoled_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_labibb_amoled>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_sw43404_amoled_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_labibb_amoled>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_sw43404_amoled_fhd_plus_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_labibb_amoled>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_dual_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_dual_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_dual_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&qupv3_se7_i2c { + status = "ok"; + st_fts@49 { + compatible = "st,fts"; + reg = <0x49>; + interrupt-parent = <&tlmm>; + interrupts = <9 0x2008>; + vdd-supply = <&pm6150_l10>; + avdd-supply = <&pm6150l_l7>; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend"; + pinctrl-0 = <&ts_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + st,irq-gpio = <&tlmm 9 0x2008>; + st,reset-gpio = <&tlmm 8 0x00>; + st,regulator_dvdd = "vdd"; + st,regulator_avdd = "avdd"; + st,x-flip; + st,y-flip; + }; +}; + +&pm6150_qg { + qcom,battery-data = <&mtp_batterydata>; +}; + +&pm6150_charger { + io-channels = <&pm6150_vadc ADC_USB_IN_V_16>, + <&pm6150_vadc ADC_USB_IN_I>, + <&pm6150_vadc ADC_CHG_TEMP>, + <&pm6150_vadc ADC_DIE_TEMP>, + <&pm6150l_vadc ADC_AMUX_THM1_PU2>; + io-channel-names = "usb_in_voltage", + "usb_in_current", + "chg_temp", + "die_temp", + "conn_temp"; + qcom,battery-data = <&mtp_batterydata>; + qcom,step-charging-enable; + qcom,sw-jeita-enable; + qcom,fcc-stepping-enable; + qcom,sec-charger-config = <3>; +}; + +&pm6150_gpios { + smb_stat { + smb_stat_default: smb_stat_default { + pins = "gpio3"; + function = "normal"; + input-enable; + bias-pull-up; + qcom,pull-up-strength = ; + power-source = <0>; + }; + }; +}; + +&qupv3_se9_i2c { + status = "ok"; + #include "smb1390.dtsi" + #include "smb1355.dtsi" +}; + +&smb1355 { + /delete-property/ interrupts; + interrupts = <0x0 0xc2 0x0 IRQ_TYPE_LEVEL_LOW>; + status = "ok"; +}; + +&smb1355_charger { + status = "ok"; +}; + +&smb1390 { + /delete-property/ interrupts; + interrupts = <0x0 0xc2 0x0 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&smb_stat_default>; + status = "ok"; +}; + +&smb1390_charger { + io-channels = <&pm6150l_vadc ADC_AMUX_THM2>; + io-channel-names = "cp_die_temp"; + status = "ok"; +}; + +&pm6150l_gpios { + key_vol_up { + key_vol_up_default: key_vol_up_default { + pins = "gpio2"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; +}; + +&soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_vol_up_default>; + + vol_up { + label = "volume_up"; + gpios = <&pm6150l_gpios 2 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + linux,can-disable; + debounce-interval = <15>; + gpio-key,wakeup; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-pinctrl.dtsi index 1cf573a8f3e722937867b616afee7f3f4f5d0065..760df24559e16e6a938d38cd062c684a0af3668c 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-pinctrl.dtsi @@ -13,7 +13,8 @@ &soc { tlmm: pinctrl@3400000 { compatible = "qcom,sdmmagpie-pinctrl"; - reg = <0x03400000 0xdc2000>; + reg = <0x03400000 0xdc2000>, <0x17c000f0 0x60>; + reg-names = "pinctrl", "spi_cfg"; interrupts = <0 208 0>; gpio-controller; #gpio-cells = <2>; @@ -867,6 +868,183 @@ }; }; + pmx_sde_te { + sde_te_active: sde_te_active { + mux { + pins = "gpio10"; + function = "mdp_vsync"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + + sde_te_suspend: sde_te_suspend { + mux { + pins = "gpio10"; + function = "mdp_vsync"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + }; + + wsa_swr_clk_pin { + wsa_swr_clk_sleep: wsa_swr_clk_sleep { + mux { + pins = "gpio49"; + function = "wsa_clk"; + }; + + config { + pins = "gpio49"; + drive-strength = <2>; + bias-bus-hold; + }; + }; + + wsa_swr_clk_active: wsa_swr_clk_active { + mux { + pins = "gpio49"; + function = "wsa_clk"; + }; + + config { + pins = "gpio49"; + drive-strength = <2>; + bias-bus-hold; + }; + }; + }; + + wsa_swr_data_pin { + wsa_swr_data_sleep: wsa_swr_data_sleep { + mux { + pins = "gpio50"; + function = "wsa_data"; + }; + + config { + pins = "gpio50"; + drive-strength = <4>; + bias-bus-hold; + }; + }; + + wsa_swr_data_active: wsa_swr_data_active { + mux { + pins = "gpio50"; + function = "wsa_data"; + }; + + config { + pins = "gpio50"; + drive-strength = <4>; + bias-bus-hold; + }; + }; + }; + + /* WSA speaker reset pins */ + spkr_1_sd_n { + spkr_1_sd_n_sleep: spkr_1_sd_n_sleep { + mux { + pins = "gpio51"; + function = "gpio"; + }; + + config { + pins = "gpio51"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; + input-enable; + }; + }; + + spkr_1_sd_n_active: spkr_1_sd_n_active { + mux { + pins = "gpio51"; + function = "gpio"; + }; + + config { + pins = "gpio51"; + drive-strength = <16>; /* 16 mA */ + bias-disable; + output-high; + }; + }; + }; + + spkr_2_sd_n { + spkr_2_sd_n_sleep: spkr_2_sd_n_sleep { + mux { + pins = "gpio52"; + function = "gpio"; + }; + + config { + pins = "gpio52"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; + input-enable; + }; + }; + + spkr_2_sd_n_active: spkr_2_sd_n_active { + mux { + pins = "gpio52"; + function = "gpio"; + }; + + config { + pins = "gpio52"; + drive-strength = <16>; /* 16 mA */ + bias-disable; + output-high; + }; + }; + }; + + wcd9xxx_intr { + wcd_intr_default: wcd_intr_default{ + mux { + pins = "gpio58"; + function = "gpio"; + }; + + config { + pins = "gpio58"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + input-enable; + }; + }; + }; + + fsa_usbc_ana_en_n@42 { + fsa_usbc_ana_en: fsa_usbc_ana_en { + mux { + pins = "gpio42"; + function = "gpio"; + }; + + config { + pins = "gpio42"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + }; + cci0_active: cci0_active { mux { /* CLK, DATA */ @@ -1200,5 +1378,63 @@ bias-disable; }; }; + + pmx_ts_active { + ts_active: ts_active { + mux { + pins = "gpio8", "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio8", "gpio9"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_int_suspend { + ts_int_suspend: ts_int_suspend { + mux { + pins = "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_reset_suspend { + ts_reset_suspend: ts_reset_suspend { + mux { + pins = "gpio8"; + function = "gpio"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + }; +}; + +&pm6150_gpios { + wcd934x_mclk { + wcd934x_mclk_default: wcd934x_mclk_default{ + pins = "gpio8"; + function = "func1"; + qcom,drive-strength = <2>; + power-source = <0>; + bias-disable; + output-low; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdmmagpie-qrd-overlay.dts index 5ddcf400e12818076304545a15320ed235758fde..1e26e1e66e9a805e50108c584f1ae1eb4bd3aade 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie-qrd-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-qrd-overlay.dts @@ -16,6 +16,7 @@ #include #include +#include "sdmmagpie-audio-overlay.dtsi" #include "sdmmagpie-qrd.dtsi" / { @@ -24,3 +25,46 @@ qcom,msm-id = <365 0x0>; qcom,board-id = <11 0>; }; + +&dsi_sw43404_amoled_video_display { + qcom,dsi-display-active; +}; + +&sm6150_snd { + qcom,model = "sm6150-wcd9375qrd-snd-card"; + qcom,audio-routing = + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Analog Mic2", + "TX DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "TX DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "TX DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "TX_AIF1 CAP", "VA_MCLK", + "TX_AIF2 CAP", "VA_MCLK", + "RX AIF1 PB", "VA_MCLK", + "RX AIF2 PB", "VA_MCLK", + "RX AIF3 PB", "VA_MCLK", + "RX AIF4 PB", "VA_MCLK", + "HPHL_OUT", "VA_MCLK", + "HPHR_OUT", "VA_MCLK", + "AUX_OUT", "VA_MCLK", + "IN1_HPHL", "HPHL_OUT", + "IN2_HPHR", "HPHR_OUT", + "IN3_AUX", "AUX_OUT", + "TX SWR_ADC0", "ADC1_OUTPUT", + "TX SWR_ADC2", "ADC2_OUTPUT", + "WSA SRC0_INP", "SRC0", + "WSA_TX DEC0_INP", "TX DEC0 MUX", + "WSA_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC0_INP", "TX DEC0 MUX", + "RX_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC2_INP", "TX DEC2 MUX", + "RX_TX DEC3_INP", "TX DEC3 MUX", + "SpkrLeft IN", "WSA_SPK1 OUT", + "WSA_SPK1 OUT", "VA_MCLK"; + qcom,wsa-max-devs = <1>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0213>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrLeft"; +}; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-qrd.dtsi index a858466d4031c2ee3fd040f646754e1d02c2f690..2608926b0d120156023714ebc54e4f205089df44 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-qrd.dtsi @@ -11,15 +11,90 @@ */ #include +#include +#include +#include #include "sdmmagpie-thermal-overlay.dtsi" +#include "sdmmagpie-sde-display.dtsi" &soc { }; +&qupv3_se7_i2c{ + status = "ok"; + st_fts@49 { + compatible = "st,fts"; + reg = <0x49>; + interrupt-parent = <&tlmm>; + interrupts = <9 0x2008>; + vdd-supply = <&pm6150_l10>; + avdd-supply = <&pm6150l_l7>; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend"; + pinctrl-0 = <&ts_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + st,irq-gpio = <&tlmm 9 0x2008>; + st,reset-gpio = <&tlmm 8 0x00>; + st,regulator_dvdd = "vdd"; + st,regulator_avdd = "avdd"; + }; +}; + +&tlmm { + pmx_ts_active { + ts_active: ts_active { + mux { + pins = "gpio8", "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio8", "gpio9"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_int_suspend { + ts_int_suspend: ts_int_suspend { + mux { + pins = "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_reset_suspend { + ts_reset_suspend: ts_reset_suspend { + mux { + pins = "gpio8"; + function = "gpio"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + +}; + &qupv3_se8_2uart { status = "ok"; }; +&qupv3_se3_4uart { + status = "ok"; +}; + &ufsphy_mem { compatible = "qcom,ufs-phy-qmp-v3"; @@ -81,3 +156,151 @@ status = "ok"; }; + +&dsi_sw43404_amoled_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_labibb_amoled>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_sw43404_amoled_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_labibb_amoled>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_sw43404_amoled_fhd_plus_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_labibb_amoled>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_dual_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_dual_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_dual_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&pm6150_qg { + qcom,battery-data = <&mtp_batterydata>; +}; + +&pm6150_charger { + io-channels = <&pm6150_vadc ADC_USB_IN_V_16>, + <&pm6150_vadc ADC_USB_IN_I>, + <&pm6150_vadc ADC_CHG_TEMP>, + <&pm6150_vadc ADC_DIE_TEMP>, + <&pm6150l_vadc ADC_AMUX_THM1_PU2>; + io-channel-names = "usb_in_voltage", + "usb_in_current", + "chg_temp", + "die_temp", + "conn_temp"; + qcom,battery-data = <&mtp_batterydata>; + qcom,sw-jeita-enable; + qcom,fcc-stepping-enable; + qcom,sec-charger-config = <1>; +}; + +&pm6150_gpios { + smb_stat { + smb_stat_default: smb_stat_default { + pins = "gpio3"; + function = "normal"; + input-enable; + bias-pull-up; + qcom,pull-up-strength = ; + power-source = <0>; + }; + }; +}; + +&qupv3_se9_i2c { + status = "ok"; + #include "smb1390.dtsi" +}; + +&smb1390 { + /delete-property/ interrupts; + interrupts = <0x0 0xc2 0x0 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&smb_stat_default>; + status = "ok"; +}; + +&smb1390_charger { + io-channels = <&pm6150l_vadc ADC_AMUX_THM2>; + io-channel-names = "cp_die_temp"; + status = "ok"; +}; + +&pm6150l_gpios { + key_vol_up { + key_vol_up_default: key_vol_up_default { + pins = "gpio2"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; +}; + +&soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_vol_up_default>; + + vol_up { + label = "volume_up"; + gpios = <&pm6150l_gpios 2 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + linux,can-disable; + debounce-interval = <15>; + gpio-key,wakeup; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-regulator.dtsi index 688682d0673843cc1a04d989329770df682158cc..404111ea44dce29471d14d40353299a87c735251 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-regulator.dtsi @@ -362,7 +362,7 @@ qcom,supported-modes = ; - qcom,mode-threshold-currents = <0 1>; + qcom,mode-threshold-currents = <0 10000>; L10A: pm6150_l10: regulator-pm6150-l10 { regulator-name = "pm6150_l10"; qcom,set = ; @@ -496,6 +496,8 @@ ; qcom,mode-threshold-currents = <0 1>; + pm6150_l17-parent-supply = <&pm6150_l11>; + L17A: pm6150_l17: regulator-pm6150-l17 { regulator-name = "pm6150_l17"; qcom,set = ; @@ -545,7 +547,7 @@ qcom,supported-modes = ; - qcom,mode-threshold-currents = <0 1>; + qcom,mode-threshold-currents = <0 10000>; L1C: pm6150l_l1: regulator-pm6150l-l1 { regulator-name = "pm6150l_l1"; qcom,set = ; @@ -564,7 +566,7 @@ qcom,supported-modes = ; - qcom,mode-threshold-currents = <0 1>; + qcom,mode-threshold-currents = <0 10000>; L2C: pm6150l_l2: regulator-pm6150l-l2 { regulator-name = "pm6150l_l2"; qcom,set = ; @@ -716,7 +718,7 @@ qcom,supported-modes = ; - qcom,mode-threshold-currents = <0 1>; + qcom,mode-threshold-currents = <0 10000>; L10C: pm6150l_l10: regulator-pm6150l-l10 { regulator-name = "pm6150l_l10"; qcom,set = ; @@ -803,8 +805,8 @@ L2F: pm8009_l2: regulator-pm8009-l2 { regulator-name = "pm8009_l2"; qcom,set = ; - regulator-min-microvolt = <1040000>; - regulator-max-microvolt = <1040000>; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; }; }; @@ -872,8 +874,8 @@ L7F: pm8009_l7: regulator-pm8009-l7 { regulator-name = "pm8009_l7"; qcom,set = ; - regulator-min-microvolt = <1696000>; - regulator-max-microvolt = <1696000>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-sde-display.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..448b055d1a2b4cd8ee6ca1a199a93daf4febea87 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-sde-display.dtsi @@ -0,0 +1,460 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "dsi-panel-sim-video.dtsi" +#include "dsi-panel-sim-cmd.dtsi" +#include "dsi-panel-sim-dsc375-cmd.dtsi" +#include "dsi-panel-sim-dualmipi-video.dtsi" +#include "dsi-panel-sim-dualmipi-cmd.dtsi" +#include "dsi-panel-sim-dualmipi-dsc375-cmd.dtsi" +#include "dsi-panel-sw43404-amoled-dsc-wqhd-video.dtsi" +#include "dsi-panel-sw43404-amoled-dsc-wqhd-cmd.dtsi" +#include "dsi-panel-sw43404-amoled-dsc-fhd-plus-cmd.dtsi" +#include + +&soc { + dsi_panel_pwr_supply: dsi_panel_pwr_supply { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "lab"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@2 { + reg = <2>; + qcom,supply-name = "ibb"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-post-on-sleep = <20>; + }; + }; + + dsi_panel_pwr_supply_no_labibb: dsi_panel_pwr_supply_no_labibb { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + }; + + dsi_panel_pwr_supply_labibb_amoled: dsi_panel_pwr_supply_labibb_amoled { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1904000>; + qcom,supply-max-voltage = <1904000>; + qcom,supply-enable-load = <32000>; + qcom,supply-disable-load = <80>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vdda-3p3"; + qcom,supply-min-voltage = <3000000>; + qcom,supply-max-voltage = <3000000>; + qcom,supply-enable-load = <13200>; + qcom,supply-disable-load = <80>; + }; + }; + + dsi_sw43404_amoled_video_display: qcom,dsi-display@0 { + label = "dsi_sw43404_amoled_video_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,dsi-panel = <&dsi_sw43404_amoled_video>; + }; + + dsi_sw43404_amoled_cmd_display: qcom,dsi-display@1 { + label = "dsi_sw43404_amoled_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,dsi-panel = <&dsi_sw43404_amoled_cmd>; + }; + + dsi_sw43404_amoled_fhd_plus_cmd_display: qcom,dsi-display@2 { + label = "dsi_sw43404_amoled_fhd_plus_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,dsi-panel = <&dsi_sw43404_amoled_fhd_plus_cmd>; + }; + + dsi_sim_vid_display: qcom,dsi-display@3 { + label = "dsi_sim_vid_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,dsi-panel = <&dsi_sim_vid>; + }; + + dsi_dual_sim_vid_display: qcom,dsi-display@4 { + label = "dsi_dual_sim_vid_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,dsi-panel = <&dsi_dual_sim_vid>; + }; + + dsi_sim_cmd_display: qcom,dsi-display@5 { + label = "dsi_sim_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,dsi-panel = <&dsi_sim_cmd>; + }; + + dsi_dual_sim_cmd_display: qcom,dsi-display@6 { + label = "dsi_dual_sim_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,dsi-panel = <&dsi_dual_sim_cmd>; + }; + + dsi_sim_dsc_375_cmd_display: qcom,dsi-display@7 { + label = "dsi_sim_dsc_375_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,dsi-panel = <&dsi_sim_dsc_375_cmd>; + }; + + dsi_dual_sim_dsc_375_cmd_display: qcom,dsi-display@8 { + label = "dsi_dual_sim_dsc_375_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,dsi-panel = <&dsi_dual_sim_dsc_375_cmd>; + }; + + sde_dsi: qcom,dsi-display { + compatible = "qcom,dsi-display"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>, + <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>, + <&mdss_dsi1_pll PCLK_MUX_1_CLK>; + clock-names = "src_byte_clk0", "src_pixel_clk0", + "src_byte_clk1", "src_pixel_clk1"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_te_active>; + pinctrl-1 = <&sde_te_suspend>; + + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; + + vddio-supply = <&pm6150_l13>; + vdda-3p3-supply = <&pm6150_l18>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + + qcom,dsi-display-list = + <&dsi_sw43404_amoled_video_display + &dsi_sw43404_amoled_cmd_display + &dsi_sw43404_amoled_fhd_plus_cmd_display + &dsi_sim_vid_display + &dsi_dual_sim_vid_display + &dsi_sim_cmd_display + &dsi_dual_sim_cmd_display + &dsi_sim_dsc_375_cmd_display + &dsi_dual_sim_dsc_375_cmd_display>; + }; + + sde_wb: qcom,wb-display@0 { + compatible = "qcom,wb-display"; + cell-index = <0>; + label = "wb_display"; + }; + + ext_disp: qcom,msm-ext-disp { + status = "disabled"; + compatible = "qcom,msm-ext-disp"; + + ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx { + compatible = "qcom,msm-ext-disp-audio-codec-rx"; + }; + }; +}; + +&sde_dp { + qcom,dp-usbpd-detection = <&pm6150_pdphy>; +}; + +&mdss_mdp { + connectors = <&sde_rscc &sde_wb &sde_dsi>; +}; + +&dsi_sw43404_amoled_video { + qcom,mdss-dsi-t-clk-post = <0x0A>; + qcom,mdss-dsi-t-clk-pre = <0x21>; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-min-refresh-rate = <55>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_hfp"; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 13 05 04 1F 1E 05 + 05 03 02 04 00]; + qcom,display-topology = <2 2 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sw43404_amoled_cmd { + qcom,ulps-enabled; + qcom,mdss-dsi-t-clk-post = <0x0A>; + qcom,mdss-dsi-t-clk-pre = <0x21>; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 13 05 04 1F 1E 05 + 05 03 02 04 00]; + qcom,display-topology = <2 2 1>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <720 180 180 180 1440 180>; + }; + }; +}; + +&dsi_sw43404_amoled_fhd_plus_cmd { + qcom,ulps-enabled; + qcom,mdss-dsi-t-clk-post = <0x0A>; + qcom,mdss-dsi-t-clk-pre = <0x21>; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 13 05 04 1F 1E 05 + 05 03 02 04 00]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <540 270 270 270 1080 270>; + }; + }; +}; + + +&dsi_sim_vid { + qcom,mdss-dsi-t-clk-post = <0x0D>; + qcom,mdss-dsi-t-clk-pre = <0x2D>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 1C 07 07 23 21 07 + 07 05 02 04 00]; + qcom,display-topology = <1 0 1>, + <2 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_sim_vid { + qcom,mdss-dsi-t-clk-post = <0x0D>; + qcom,mdss-dsi-t-clk-pre = <0x2D>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 1C 07 07 23 21 07 + 07 05 02 04 00]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sim_cmd { + qcom,mdss-dsi-t-clk-post = <0x0C>; + qcom,mdss-dsi-t-clk-pre = <0x29>; + qcom,ulps-enabled; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 1A 06 06 22 20 07 + 07 04 02 04 00]; + qcom,display-topology = <1 1 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <720 40 720 40 720 40>; + qcom,partial-update-enabled = "single_roi"; + }; + + timing@1{ + qcom,mdss-dsi-panel-phy-timings = [00 1A 06 06 22 20 07 + 07 04 02 04 00]; + qcom,display-topology = <1 1 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <540 40 540 40 540 40>; + qcom,partial-update-enabled = "single_roi"; + }; + + timing@2{ + qcom,mdss-dsi-panel-phy-timings = [00 1A 06 06 22 20 07 + 07 04 02 04 00]; + qcom,display-topology = <1 1 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <360 40 360 40 360 40>; + qcom,partial-update-enabled = "single_roi"; + }; + }; +}; + +&dsi_dual_sim_cmd { + qcom,mdss-dsi-t-clk-post = <0x0D>; + qcom,mdss-dsi-t-clk-pre = <0x2D>; + qcom,ulps-enabled; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 24 09 09 26 24 09 + 09 06 02 04 00]; + qcom,display-topology = <2 0 2>; + qcom,default-topology-index = <0>; + }; + timing@1{ + qcom,mdss-dsi-panel-phy-timings = [00 1C 07 07 23 21 07 + 07 05 02 04 00]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + timing@2{ + qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06 + 06 04 02 04 00]; + qcom,display-topology = <2 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sim_dsc_375_cmd { + qcom,mdss-dsi-t-clk-post = <0x0D>; + qcom,mdss-dsi-t-clk-pre = <0x2D>; + qcom,ulps-enabled; + qcom,mdss-dsi-display-timings { + timing@0 { /* 1080p */ + qcom,mdss-dsi-panel-phy-timings = [00 1A 06 06 22 20 07 + 07 04 02 04 00]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + }; + timing@1 { /* qhd */ + qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1F 05 + 05 03 02 04 00]; + qcom,display-topology = <1 1 1>, + <2 2 1>, /* dsc merge */ + <2 1 1>; /* 3d mux */ + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_sim_dsc_375_cmd { + qcom,mdss-dsi-t-clk-post = <0x0D>; + qcom,mdss-dsi-t-clk-pre = <0x2D>; + qcom,ulps-enabled; + qcom,mdss-dsi-display-timings { + timing@0 { /* qhd */ + qcom,mdss-dsi-panel-phy-timings = [00 1C 07 07 23 21 07 + 07 05 02 04 00]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + timing@1 { /* 4k */ + qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06 + 06 04 02 04 00]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-sde-pll.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-sde-pll.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..19070c4c3f6b8cc1b4fd3ed0feca07b2d5b91813 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-sde-pll.dtsi @@ -0,0 +1,110 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + mdss_dsi0_pll: qcom,mdss_dsi_pll@ae94a00 { + compatible = "qcom,mdss_dsi_pll_10nm"; + label = "MDSS DSI 0 PLL"; + cell-index = <0>; + #clock-cells = <1>; + reg = <0xae94a00 0x1e0>, + <0xae94400 0x800>, + <0xaf03000 0x8>; + reg-names = "pll_base", "phy_base", "gdsc_base"; + clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>; + clock-names = "iface_clk"; + clock-rate = <0>; + gdsc-supply = <&mdss_core_gdsc>; + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + mdss_dsi1_pll: qcom,mdss_dsi_pll@ae96a00 { + compatible = "qcom,mdss_dsi_pll_10nm"; + label = "MDSS DSI 1 PLL"; + cell-index = <1>; + #clock-cells = <1>; + reg = <0xae96a00 0x1e0>, + <0xae96400 0x800>, + <0xaf03000 0x8>; + reg-names = "pll_base", "phy_base", "gdsc_base"; + clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>; + clock-names = "iface_clk"; + clock-rate = <0>; + gdsc-supply = <&mdss_core_gdsc>; + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + mdss_dp_pll: qcom,mdss_dp_pll@ae90000 { + status = "disabled"; + compatible = "qcom,mdss_dp_pll_10nm"; + label = "MDSS DP PLL"; + cell-index = <0>; + #clock-cells = <1>; + + reg = <0x088ea000 0x200>, + <0x088eaa00 0x200>, + <0x088ea200 0x200>, + <0x088ea600 0x200>, + <0xaf03000 0x8>; + reg-names = "pll_base", "phy_base", "ln_tx0_base", + "ln_tx1_base", "gdsc_base"; + + gdsc-supply = <&mdss_core_gdsc>; + + clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; + clock-names = "iface_clk", "ref_clk_src", "ref_clk", + "cfg_ahb_clk", "pipe_clk"; + clock-rate = <0>; + + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + + }; + }; + +}; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-sde.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-sde.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..bde43c1e7fe0757cdd323141c96086261489e2e7 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-sde.dtsi @@ -0,0 +1,666 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + mdss_mdp: qcom,mdss_mdp@ae00000 { + compatible = "qcom,sde-kms"; + reg = <0x0ae00000 0x84208>, + <0x0aeb0000 0x2008>, + <0x0aeac000 0x214>; + reg-names = "mdp_phys", + "vbif_phys", + "regdma_phys"; + + clocks = + <&clock_gcc GCC_DISP_AHB_CLK>, + <&clock_gcc GCC_DISP_HF_AXI_CLK>, + <&clock_gcc GCC_DISP_SF_AXI_CLK>, + <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_dispcc DISP_CC_MDSS_MDP_CLK>, + <&clock_dispcc DISP_CC_MDSS_VSYNC_CLK>, + <&clock_dispcc DISP_CC_MDSS_MDP_LUT_CLK>, + <&clock_dispcc DISP_CC_MDSS_ROT_CLK>; + clock-names = "gcc_iface", "gcc_bus", "gcc_nrt_bus", + "iface_clk", "core_clk", "vsync_clk", + "lut_clk", "rot_clk"; + clock-rate = <0 0 0 0 300000000 19200000 200000000 + 200000000>; + clock-max-rate = <0 0 0 0 430000000 19200000 430000000 + 430000000>; + + sde-vdd-supply = <&mdss_core_gdsc>; + + /* interrupt config */ + interrupts = <0 83 0>; + interrupt-controller; + #interrupt-cells = <1>; + iommus = <&apps_smmu 0x800 0x440>; + + #address-cells = <1>; + #size-cells = <0>; + + #power-domain-cells = <0>; + + /* hw blocks */ + qcom,sde-off = <0x1000>; + qcom,sde-len = <0x45c>; + + qcom,sde-ctl-off = <0x2000 0x2200 0x2400 + 0x2600 0x2800 0x2a00>; + qcom,sde-ctl-size = <0x1e0>; + qcom,sde-ctl-display-pref = "primary", "none", "none", + "none", "none"; + + qcom,sde-mixer-off = <0x45000 0x46000 0x47000 + 0x48000 0x0 0x0>; + qcom,sde-mixer-size = <0x320>; + qcom,sde-mixer-display-pref = "primary", "primary", "none", + "none", "none", "none"; + + qcom,sde-mixer-cwb-pref = "none", "none", "cwb", + "cwb", "none", "none"; + + qcom,sde-dspp-top-off = <0x1300>; + qcom,sde-dspp-top-size = <0x80>; + qcom,sde-dspp-off = <0x55000 0x57000>; + qcom,sde-dspp-size = <0x1800>; + + qcom,sde-dest-scaler-top-off = <0x00061000>; + qcom,sde-dest-scaler-top-size = <0x1c>; + qcom,sde-dest-scaler-off = <0x800 0x1000>; + qcom,sde-dest-scaler-size = <0xa0>; + + qcom,sde-wb-off = <0x66000>; + qcom,sde-wb-size = <0x2c8>; + qcom,sde-wb-xin-id = <6>; + qcom,sde-wb-id = <2>; + qcom,sde-wb-clk-ctrl = <0x3b8 24>; + + qcom,sde-intf-off = <0x6b000 0x6b800 + 0x6c000 0x6c800>; + qcom,sde-intf-size = <0x2b8>; + qcom,sde-intf-type = "dp", "dsi", "dsi", "dp"; + + qcom,sde-pp-off = <0x71000 0x71800 + 0x72000 0x72800>; + qcom,sde-pp-slave = <0x0 0x0 0x0 0x0>; + qcom,sde-pp-size = <0xd4>; + qcom,sde-pp-merge-3d-id = <0x0 0x0 0x1 0x1>; + + qcom,sde-merge-3d-off = <0x84000 0x84100>; + qcom,sde-merge-3d-size = <0x100>; + + qcom,sde-te2-off = <0x2000 0x2000 0x0 0x0>; + + qcom,sde-cdm-off = <0x7a200>; + qcom,sde-cdm-size = <0x224>; + + qcom,sde-dsc-off = <0x81000 0x81400>; + qcom,sde-dsc-size = <0x140>; + + qcom,sde-dither-off = <0x30e0 0x30e0 0x30e0 0x30e0>; + qcom,sde-dither-version = <0x00010000>; + qcom,sde-dither-size = <0x20>; + + qcom,sde-sspp-type = "vig", "vig", "dma", "dma", "dma"; + + qcom,sde-sspp-off = <0x5000 0x7000 0x25000 0x27000 + 0x29000>; + qcom,sde-sspp-src-size = <0x1f0>; + + qcom,sde-sspp-xin-id = <0 4 1 5 9>; + qcom,sde-sspp-excl-rect = <1 1 1 1 1>; + qcom,sde-sspp-smart-dma-priority = <4 5 1 2 3>; + qcom,sde-smart-dma-rev = "smart_dma_v2p5"; + + qcom,sde-mixer-pair-mask = <2 1 4 3 0 0>; + + qcom,sde-mixer-blend-op-off = <0x20 0x38 0x50 0x68 0x80 0x98 + 0xb0 0xc8 0xe0 0xf8 0x110>; + + qcom,sde-max-per-pipe-bw-kbps = <4500000 + 4500000 4500000 + 4500000 4500000>; + + /* offsets are relative to "mdp_phys + qcom,sde-off */ + qcom,sde-sspp-clk-ctrl = + <0x2ac 0>, <0x2b4 0>, <0x2ac 8>, <0x2b4 8>, + <0x2bc 8>; + qcom,sde-sspp-csc-off = <0x1a00>; + qcom,sde-csc-type = "csc-10bit"; + qcom,sde-qseed-type = "qseedv3lite"; + qcom,sde-sspp-qseed-off = <0xa00>; + qcom,sde-mixer-linewidth = <2560>; + qcom,sde-sspp-linewidth = <2880>; + qcom,sde-wb-linewidth = <4096>; + qcom,sde-mixer-blendstages = <0xb>; + qcom,sde-highest-bank-bit = <0x1>; + qcom,sde-ubwc-version = <0x200>; + qcom,sde-panic-per-pipe; + qcom,sde-has-cdp; + qcom,sde-has-src-split; + qcom,sde-pipe-order-version = <0x1>; + qcom,sde-has-dim-layer; + qcom,sde-has-idle-pc; + qcom,sde-has-dest-scaler; + qcom,sde-max-dest-scaler-input-linewidth = <2048>; + qcom,sde-max-dest-scaler-output-linewidth = <2560>; + qcom,sde-max-bw-low-kbps = <12800000>; + qcom,sde-max-bw-high-kbps = <12800000>; + qcom,sde-min-core-ib-kbps = <2400000>; + qcom,sde-min-llcc-ib-kbps = <800000>; + qcom,sde-min-dram-ib-kbps = <800000>; + qcom,sde-dram-channels = <2>; + qcom,sde-num-nrt-paths = <0>; + qcom,sde-dspp-ad-version = <0x00040000>; + qcom,sde-dspp-ad-off = <0x28000 0x27000>; + + qcom,sde-vbif-off = <0>; + qcom,sde-vbif-size = <0x1040>; + qcom,sde-vbif-id = <0>; + qcom,sde-vbif-memtype-0 = <3 3 3 3 3 3 3 3>; + qcom,sde-vbif-memtype-1 = <3 3 3 3 3 3>; + + qcom,sde-vbif-qos-rt-remap = <3 3 4 4 5 5 6 6>; + qcom,sde-vbif-qos-nrt-remap = <3 3 3 3 3 3 3 3>; + + /* macrotile & macrotile-qseed has the same configs */ + qcom,sde-danger-lut = <0x0000000f 0x0000ffff + 0x00000000 0x00000000 0x0000ffff>; + + qcom,sde-safe-lut-linear = <0 0xfff8>; + qcom,sde-safe-lut-macrotile = <0 0xf000>; + /* same as safe-lut-macrotile */ + qcom,sde-safe-lut-macrotile-qseed = <0 0xf000>; + qcom,sde-safe-lut-nrt = <0 0xffff>; + qcom,sde-safe-lut-cwb = <0 0xffff>; + + qcom,sde-qos-lut-linear = <0 0x00112222 0x22223357>; + qcom,sde-qos-lut-macrotile = <0 0x00112233 0x44556677>; + qcom,sde-qos-lut-macrotile-qseed = <0 0x00112233 0x66777777>; + qcom,sde-qos-lut-nrt = <0 0x00000000 0x00000000>; + qcom,sde-qos-lut-cwb = <0 0x75300000 0x00000000>; + + qcom,sde-cdp-setting = <1 1>, <1 0>; + + qcom,sde-qos-cpu-mask = <0x3>; + qcom,sde-qos-cpu-dma-latency = <300>; + + /* offsets are relative to "mdp_phys + qcom,sde-off */ + + qcom,sde-reg-dma-off = <0>; + qcom,sde-reg-dma-version = <0x00010001>; + qcom,sde-reg-dma-trigger-off = <0x119c>; + + qcom,sde-secure-sid-mask = <0x4400801>; + + qcom,sde-sspp-vig-blocks { + qcom,sde-vig-csc-off = <0x1a00>; + qcom,sde-vig-qseed-off = <0xa00>; + qcom,sde-vig-qseed-size = <0xa0>; + qcom,sde-vig-gamut = <0x1d00 0x00050000>; + qcom,sde-vig-igc = <0x1d00 0x00050000>; + qcom,sde-vig-inverse-pma; + }; + + qcom,sde-sspp-dma-blocks { + dgm@0 { + qcom,sde-dma-igc = <0x400 0x00050000>; + qcom,sde-dma-gc = <0x600 0x00050000>; + qcom,sde-dma-inverse-pma; + qcom,sde-dma-csc-off = <0x200>; + }; + dgm@1 { + qcom,sde-dma-igc = <0x1400 0x00050000>; + qcom,sde-dma-gc = <0x600 0x00050000>; + qcom,sde-dma-inverse-pma; + qcom,sde-dma-csc-off = <0x1200>; + }; + }; + + qcom,sde-dspp-blocks { + qcom,sde-dspp-igc = <0x0 0x00030001>; + qcom,sde-dspp-hsic = <0x800 0x00010007>; + qcom,sde-dspp-memcolor = <0x880 0x00010007>; + qcom,sde-dspp-hist = <0x800 0x00010007>; + qcom,sde-dspp-sixzone= <0x900 0x00010007>; + qcom,sde-dspp-vlut = <0xa00 0x00010008>; + qcom,sde-dspp-gamut = <0x1000 0x00040001>; + qcom,sde-dspp-pcc = <0x1700 0x00040000>; + qcom,sde-dspp-gc = <0x17c0 0x00010008>; + qcom,sde-dspp-dither = <0x82c 0x00010007>; + }; + + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "sde-vdd"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + + smmu_sde_sec: qcom,smmu_sde_sec_cb { + compatible = "qcom,smmu_sde_sec"; + iommus = <&apps_smmu 0x801 0x440>; + }; + + /* data and reg bus scale settings */ + qcom,sde-data-bus { + qcom,msm-bus,name = "mdss_sde"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, <23 512 0 0>, + <22 512 0 6400000>, <23 512 0 6400000>, + <22 512 0 6400000>, <23 512 0 6400000>; + }; + + qcom,sde-reg-bus { + qcom,msm-bus,name = "mdss_reg"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>, + <1 590 0 150000>, + <1 590 0 300000>; + }; + }; + + sde_rscc: qcom,sde_rscc@af20000 { + cell-index = <0>; + compatible = "qcom,sde-rsc"; + reg = <0xaf20000 0x1c44>, + <0xaf30000 0x3fd4>; + reg-names = "drv", "wrapper"; + qcom,sde-rsc-version = <2>; + + vdd-supply = <&mdss_core_gdsc>; + clocks = <&clock_dispcc DISP_CC_MDSS_RSCC_VSYNC_CLK>, + <&clock_dispcc DISP_CC_MDSS_NON_GDSC_AHB_CLK>, + <&clock_dispcc DISP_CC_MDSS_RSCC_AHB_CLK>; + clock-names = "vsync_clk", "gdsc_clk", "iface_clk"; + clock-rate = <0 0 0>; + + qcom,sde-dram-channels = <2>; + + mboxes = <&disp_rsc 0>; + mbox-names = "disp_rsc"; + + /* data and reg bus scale settings */ + qcom,sde-data-bus { + qcom,msm-bus,name = "disp_rsc_mnoc"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <20003 20515 0 0>, <20004 20515 0 0>, + <20003 20515 0 6400000>, <20004 20515 0 6400000>, + <20003 20515 0 6400000>, <20004 20515 0 6400000>; + }; + + qcom,sde-llcc-bus { + qcom,msm-bus,name = "disp_rsc_llcc"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <20001 20513 0 0>, + <20001 20513 0 6400000>, + <20001 20513 0 6400000>; + }; + + qcom,sde-ebi-bus { + qcom,msm-bus,name = "disp_rsc_ebi"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <20000 20512 0 0>, + <20000 20512 0 6400000>, + <20000 20512 0 6400000>; + }; + }; + + mdss_rotator: qcom,mdss_rotator@ae00000 { + compatible = "qcom,sde_rotator"; + reg = <0x0ae00000 0xac000>, + <0x0aeb8000 0x3000>; + reg-names = "mdp_phys", + "rot_vbif_phys"; + + #list-cells = <1>; + + qcom,mdss-rot-mode = <1>; + qcom,mdss-highest-bank-bit = <0x1>; + + /* Bus Scale Settings */ + qcom,msm-bus,name = "mdss_rotator"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <25 512 0 0>, + <25 512 0 6400000>, + <25 512 0 6400000>; + + rot-vdd-supply = <&mdss_core_gdsc>; + qcom,supply-names = "rot-vdd"; + + clocks = + <&clock_gcc GCC_DISP_AHB_CLK>, + <&clock_gcc GCC_DISP_SF_AXI_CLK>, + <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_dispcc DISP_CC_MDSS_ROT_CLK>; + clock-names = "gcc_iface", "gcc_bus", + "iface_clk", "rot_clk"; + + interrupt-parent = <&mdss_mdp>; + interrupts = <2 0>; + + power-domains = <&mdss_mdp>; + + /* Offline rotator QoS setting */ + qcom,mdss-rot-vbif-qos-setting = <3 3 3 3 3 3 3 3>; + qcom,mdss-rot-vbif-memtype = <3 3>; + qcom,mdss-rot-cdp-setting = <1 1>; + qcom,mdss-rot-qos-lut = <0x0 0x0 0x0 0x0>; + qcom,mdss-rot-danger-lut = <0x0 0x0>; + qcom,mdss-rot-safe-lut = <0x0000ffff 0x0000ffff>; + + qcom,mdss-default-ot-rd-limit = <32>; + qcom,mdss-default-ot-wr-limit = <32>; + + qcom,mdss-sbuf-headroom = <20>; + + cache-slice-names = "rotator"; + cache-slices = <&llcc 4>; + + /* reg bus scale settings */ + rot_reg: qcom,rot-reg-bus { + qcom,msm-bus,name = "mdss_rot_reg"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>; + }; + + smmu_rot_unsec: qcom,smmu_rot_unsec_cb { + compatible = "qcom,smmu_sde_rot_unsec"; + iommus = <&apps_smmu 0x1020 0x0>; + }; + + smmu_rot_sec: qcom,smmu_rot_sec_cb { + compatible = "qcom,smmu_sde_rot_sec"; + iommus = <&apps_smmu 0x1021 0x0>; + }; + }; + + mdss_dsi0: qcom,mdss_dsi_ctrl0@ae94000 { + compatible = "qcom,dsi-ctrl-hw-v2.3"; + label = "dsi-ctrl-0"; + cell-index = <0>; + reg = <0xae94000 0x400>, + <0xaf08000 0x4>; + reg-names = "dsi_ctrl", "disp_cc_base"; + interrupt-parent = <&mdss_mdp>; + interrupts = <4 0>; + vdda-1p2-supply = <&pm6150l_l3>; + clocks = <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK>, + <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, + <&clock_dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK>, + <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>, + <&clock_dispcc DISP_CC_MDSS_ESC0_CLK>; + clock-names = "byte_clk", "byte_clk_rcg", "byte_intf_clk", + "pixel_clk", "pixel_clk_rcg", + "esc_clk"; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1144000>; + qcom,supply-max-voltage = <1232000>; + qcom,supply-enable-load = <21800>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + mdss_dsi1: qcom,mdss_dsi_ctrl1@ae96000 { + compatible = "qcom,dsi-ctrl-hw-v2.3"; + label = "dsi-ctrl-1"; + cell-index = <1>; + reg = <0xae96000 0x400>, + <0xaf08000 0x4>; + reg-names = "dsi_ctrl", "disp_cc_base"; + interrupt-parent = <&mdss_mdp>; + interrupts = <5 0>; + vdda-1p2-supply = <&pm6150l_l3>; + clocks = <&clock_dispcc DISP_CC_MDSS_BYTE1_CLK>, + <&clock_dispcc DISP_CC_MDSS_BYTE1_CLK_SRC>, + <&clock_dispcc DISP_CC_MDSS_BYTE1_INTF_CLK>, + <&clock_dispcc DISP_CC_MDSS_PCLK1_CLK>, + <&clock_dispcc DISP_CC_MDSS_PCLK1_CLK_SRC>, + <&clock_dispcc DISP_CC_MDSS_ESC1_CLK>; + clock-names = "byte_clk", "byte_clk_rcg", "byte_intf_clk", + "pixel_clk", "pixel_clk_rcg", + "esc_clk"; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1144000>; + qcom,supply-max-voltage = <1232000>; + qcom,supply-enable-load = <21800>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + mdss_dsi_phy0: qcom,mdss_dsi_phy0@ae94400 { + compatible = "qcom,dsi-phy-v3.0"; + label = "dsi-phy-0"; + cell-index = <0>; + reg = <0xae94400 0x7c0>; + reg-names = "dsi_phy"; + gdsc-supply = <&mdss_core_gdsc>; + vdda-0p9-supply = <&pm6150_l4>; + qcom,platform-strength-ctrl = [55 03 + 55 03 + 55 03 + 55 03 + 55 00]; + qcom,platform-lane-config = [00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 80]; + qcom,platform-regulator-settings = [1d 1d 1d 1d 1d]; + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <824000>; + qcom,supply-max-voltage = <920000>; + qcom,supply-enable-load = <36000>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + mdss_dsi_phy1: qcom,mdss_dsi_phy1@ae96400 { + compatible = "qcom,dsi-phy-v3.0"; + label = "dsi-phy-1"; + cell-index = <1>; + reg = <0xae96400 0x7c0>; + reg-names = "dsi_phy"; + gdsc-supply = <&mdss_core_gdsc>; + vdda-0p9-supply = <&pm6150_l4>; + qcom,platform-strength-ctrl = [55 03 + 55 03 + 55 03 + 55 03 + 55 00]; + qcom,platform-lane-config = [00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 80]; + qcom,platform-regulator-settings = [1d 1d 1d 1d 1d]; + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <824000>; + qcom,supply-max-voltage = <920000>; + qcom,supply-enable-load = <36000>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + sde_dp: qcom,dp_display@0{ + status = "disabled"; + cell-index = <0>; + compatible = "qcom,dp-display"; + + vdda-1p2-supply = <&pm6150l_l3>; + vdda-0p9-supply = <&pm6150_l4>; + + reg = <0xae90000 0x0dc>, + <0xae90200 0x0c0>, + <0xae90400 0x508>, + <0xae90a00 0x094>, + <0x88eaa00 0x200>, + <0x88ea200 0x200>, + <0x88ea600 0x200>, + <0xaf02000 0x1a0>, + <0x780000 0x621c>, + <0x88ea040 0x10>, + <0x88e8000 0x20>, + <0x0aee1000 0x034>, + <0xae91000 0x094>; + /* dp_ctrl: dp_ahb, dp_aux, dp_link, dp_p0 */ + reg-names = "dp_ahb", "dp_aux", "dp_link", + "dp_p0", "dp_phy", "dp_ln_tx0", "dp_ln_tx1", + "dp_mmss_cc", "qfprom_physical", "dp_pll", + "usb3_dp_com", "hdcp_physical", "dp_p1"; + + interrupt-parent = <&mdss_mdp>; + interrupts = <12 0>; + + qcom,phy-version = <0x420>; + qcom,aux-cfg0-settings = [20 00]; + qcom,aux-cfg1-settings = [24 13]; + qcom,aux-cfg2-settings = [28 24]; + qcom,aux-cfg3-settings = [2c 00]; + qcom,aux-cfg4-settings = [30 0a]; + qcom,aux-cfg5-settings = [34 26]; + qcom,aux-cfg6-settings = [38 0a]; + qcom,aux-cfg7-settings = [3c 03]; + qcom,aux-cfg8-settings = [40 b7]; + qcom,aux-cfg9-settings = [44 03]; + + qcom,max-pclk-frequency-khz = <675000>; + + qcom,mst-enable; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <21800>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <880000>; + qcom,supply-enable-load = <36000>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-thermal-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-thermal-overlay.dtsi index fe5a89d4ced9d496674b29b7d9548d9097d70782..f47d16937319f90936558fff5b4e5a3a6c7e578e 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie-thermal-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-thermal-overlay.dtsi @@ -176,3 +176,7 @@ }; }; }; + +&mdss_mdp { + #cooling-cells = <2>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-usb.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-usb.dtsi index 9e7ded972c94fcd76f133d4a2c1ec939b3b3135a..7e6621765ccb9e3ce14bc2777af18c2b4d61147c 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie-usb.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-usb.dtsi @@ -343,9 +343,10 @@ <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, <&clock_rpmh RPMH_CXO_CLK>, <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>, - <&clock_gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>; + <&clock_gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>; clock-names = "aux_clk", "pipe_clk", "ref_clk_src", - "ref_clk", "com_aux_clk"; + "ref_clk", "com_aux_clk", "cfg_ahb_clk"; resets = <&clock_gcc GCC_USB3_DP_PHY_PRIM_BCR>, <&clock_gcc GCC_USB3_PHY_PRIM_BCR>; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-usbc-idp-overlay.dts b/arch/arm64/boot/dts/qcom/sdmmagpie-usbc-idp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..c6d7615903fd0486191fa7f71a1ba3bda3f4c245 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-usbc-idp-overlay.dts @@ -0,0 +1,25 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include + +#include "sdmmagpie-idp.dtsi" + +/ { + model = "USBC Audio IDP"; + compatible = "qcom,sdmmagpie-idp", "qcom,sdmmagpie", "qcom,idp"; + qcom,msm-id = <365 0x0>; + qcom,board-id = <34 2>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-usbc-idp.dts b/arch/arm64/boot/dts/qcom/sdmmagpie-usbc-idp.dts new file mode 100644 index 0000000000000000000000000000000000000000..5ebc8612ec0340f8c4338fcc56bf098b07a083ae --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-usbc-idp.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sdmmagpie.dtsi" +#include "sdmmagpie-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDMMAGPIE PM6150 USBC Audio IDP"; + compatible = "qcom,sdmmagpie-idp", "qcom,sdmmagpie", "qcom,idp"; + qcom,board-id = <34 2>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie-vidc.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie-vidc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..558f92e286f4b10825e7e9487aeedeaee209c59f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdmmagpie-vidc.dtsi @@ -0,0 +1,219 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include + +&soc { + msm_vidc0: qcom,vidc0 { + compatible = "qcom,msm-vidc", "qcom,sdmmagpie-vidc"; + status = "ok"; + sku-index = <0>; + reg = <0xaa00000 0x200000>; + interrupts = ; + + /* Supply */ + iris-ctl-supply = <&mvsc_gdsc>; + vcodec-supply = <&mvs0_gdsc>; + cvp-supply = <&mvs1_gdsc>; + + /* Clocks */ + clock-names = "video_cc_mvsc_ctl_axi", "video_cc_mvs0_ctl_axi", + "video_cc_mvs1_ctl_axi", "core_clk", "vcodec_clk", + "cvp_clk", "iface_clk"; + clocks = <&clock_videocc VIDEO_CC_MVSC_CTL_AXI_CLK>, + <&clock_videocc VIDEO_CC_MVS0_AXI_CLK>, + <&clock_videocc VIDEO_CC_MVS1_AXI_CLK>, + <&clock_videocc VIDEO_CC_MVSC_CORE_CLK>, + <&clock_videocc VIDEO_CC_MVS0_CORE_CLK>, + <&clock_videocc VIDEO_CC_MVS1_CORE_CLK>, + <&clock_videocc VIDEO_CC_VENUS_AHB_CLK>; + + qcom,proxy-clock-names = "video_cc_mvsc_ctl_axi", + "video_cc_mvs0_ctl_axi", "video_cc_mvs1_ctl_axi", + "core_clk", "vcodec_clk", "cvp_clk", "iface_clk"; + + qcom,clock-configs = <0x0 0x0 0x0 0x1 0x1 0x1 0x0>; + qcom,allowed-clock-rates = <240000000 338000000 + 365000000 444000000 533000000>; + + /* Buses */ + bus_cnoc { + compatible = "qcom,msm-vidc,bus"; + label = "cnoc"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "performance"; + qcom,bus-range-kbps = <1000 1000>; + }; + + venus_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "msm-vidc-ddr"; + qcom,bus-range-kbps = <1000 6533000>; + }; + arm9_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-arm9-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "performance"; + qcom,bus-range-kbps = <1000 1000>; + }; + + /* MMUs */ + non_secure_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_ns"; + iommus = <&apps_smmu 0x1080 0x60>; + buffer-types = <0xfff>; + virtual-addr-pool = <0x25800000 0xba800000>; + }; + + secure_non_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_non_pixel"; + iommus = <&apps_smmu 0x1084 0x60>; + buffer-types = <0x480>; + virtual-addr-pool = <0x1000000 0x24800000>; + qcom,secure-context-bank; + }; + + secure_bitstream_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_bitstream"; + iommus = <&apps_smmu 0x1081 0x4>; + buffer-types = <0x241>; + virtual-addr-pool = <0x0 0xe0000000>; + qcom,secure-context-bank; + }; + + secure_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_pixel"; + iommus = <&apps_smmu 0x1083 0x20>; + buffer-types = <0x106>; + virtual-addr-pool = <0x0 0xe0000000>; + qcom,secure-context-bank; + }; + + /* Memory Heaps */ + qcom,msm-vidc,mem_cdsp { + compatible = "qcom,msm-vidc,mem-cdsp"; + memory-region = <&cdsp_mem>; + }; + }; + + msm_vidc1: qcom,vidc1 { + compatible = "qcom,msm-vidc", "qcom,sdmmagpie-vidc"; + status = "ok"; + sku-index = <1>; + reg = <0xaa00000 0x200000>; + interrupts = ; + + /* Supply */ + iris-ctl-supply = <&mvsc_gdsc>; + vcodec-supply = <&mvs0_gdsc>; + cvp-supply = <&mvs1_gdsc>; + + /* Clocks */ + clock-names = "gcc_video_axic", "gcc_video_axi0", + "gcc_video_axi1", "core_clk", "vcodec_clk", + "cvp_clk"; + clocks = <&clock_videocc VIDEO_CC_MVSC_CTL_AXI_CLK>, + <&clock_videocc VIDEO_CC_MVS0_AXI_CLK>, + <&clock_videocc VIDEO_CC_MVS1_AXI_CLK>, + <&clock_videocc VIDEO_CC_MVSC_CORE_CLK>, + <&clock_videocc VIDEO_CC_MVS0_CORE_CLK>, + <&clock_videocc VIDEO_CC_MVS1_CORE_CLK>; + qcom,proxy-clock-names = "gcc_video_axic", + "gcc_video_axi0", "gcc_video_axi1", + "core_clk", "vcodec_clk", "cvp_clk"; + + qcom,clock-configs = <0x0 0x0 0x0 0x1 0x1 0x1>; + qcom,allowed-clock-rates = <240000000 338000000 + 365000000 444000000 533000000>; + + /* Buses */ + bus_cnoc { + compatible = "qcom,msm-vidc,bus"; + label = "cnoc"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "performance"; + qcom,bus-range-kbps = <1000 1000>; + }; + + venus_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "msm-vidc-ddr"; + qcom,bus-range-kbps = <1000 6533000>; + }; + arm9_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-arm9-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "performance"; + qcom,bus-range-kbps = <1000 1000>; + }; + + /* MMUs */ + non_secure_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_ns"; + iommus = <&apps_smmu 0x2300 0x60>; + buffer-types = <0xfff>; + virtual-addr-pool = <0x25800000 0xba800000>; + }; + + secure_non_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_non_pixel"; + iommus = <&apps_smmu 0x2304 0x60>; + buffer-types = <0x480>; + virtual-addr-pool = <0x1000000 0x24800000>; + qcom,secure-context-bank; + }; + + secure_bitstream_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_bitstream"; + iommus = <&apps_smmu 0x2301 0x4>; + buffer-types = <0x241>; + virtual-addr-pool = <0x0 0xe0000000>; + qcom,secure-context-bank; + }; + + secure_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_pixel"; + iommus = <&apps_smmu 0x2303 0x20>; + buffer-types = <0x106>; + virtual-addr-pool = <0x0 0xe0000000>; + qcom,secure-context-bank; + }; + + /* Memory Heaps */ + qcom,msm-vidc,mem_cdsp { + compatible = "qcom,msm-vidc,mem-cdsp"; + memory-region = <&cdsp_mem>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi index a3e29153fe8286a44a629d373183dff2af45b405..a39293c8c554be7518a532f2f7c572c2b7b77f8c 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi @@ -22,6 +22,11 @@ #include #include #include +#include +#include + +#define MHZ_TO_MBPS(mhz, w) ((mhz * 1000000 * w) / (1024 * 1024)) +#define BW_OPP_ENTRY(mhz, w) opp-mhz {opp-hz = /bits/ 64 ;} / { model = "Qualcomm Technologies, Inc. SDMMAGPIE"; @@ -41,6 +46,9 @@ sdhc1 = &sdhc_1; /* SDC1 eMMC slot */ sdhc2 = &sdhc_2; /* SDC2 SD Card slot */ ufshc1 = &ufshc_mem; /* Embedded UFS slot */ + swr0 = &swr0; + swr1 = &swr1; + swr2 = &swr2; }; cpus { @@ -381,12 +389,15 @@ CPU_COST_0: core-cost0 { busy-cost-data = < - 300000 18 + 300000 10 + 576000 18 768000 23 1017600 36 1248000 52 + 1324800 67 1497600 76 1612800 92 + 1708800 113 1804800 119 >; idle-cost-data = < @@ -397,10 +408,15 @@ CPU_COST_1: core-cost1 { busy-cost-data = < 300000 166 + 652800 242 806400 293 + 979200 424 1094400 470 + 1209600 621 1324800 676 + 1555200 973 1708800 1060 + 1843800 1298 1939200 1362 2169600 1801 2361600 2326 @@ -414,11 +430,14 @@ CLUSTER_COST_0: cluster-cost0 { busy-cost-data = < 300000 5 + 576000 5 768000 5 1017600 7 1248000 8 + 1324800 10 1497600 10 1612800 12 + 1708800 14 1804800 14 >; idle-cost-data = < @@ -429,10 +448,15 @@ CLUSTER_COST_1: cluster-cost1 { busy-cost-data = < 300000 19 + 652800 21 806400 21 + 979200 25 1094400 26 + 1209600 32 1324800 33 + 1555200 41 1708800 43 + 1843800 49 1939200 50 2169600 60 2361600 62 @@ -638,6 +662,12 @@ linux,cma-default; }; }; + + mtp_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "qg-batterydata-alium-3600mah.dtsi" + #include "qg-batterydata-mlp356477-2800mah.dtsi" + }; }; &soc { @@ -666,6 +696,33 @@ interrupt-controller; }; + qcom,memshare { + compatible = "qcom,memshare"; + + qcom,client_1 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x0>; + qcom,client-id = <0>; + qcom,allocate-boot-time; + label = "modem"; + }; + + qcom,client_2 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x0>; + qcom,client-id = <2>; + label = "modem"; + }; + + mem_client_3_size: qcom,client_3 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x500000>; + qcom,client-id = <1>; + qcom,allocate-on-request; + label = "modem"; + }; + }; + timer { compatible = "arm,armv8-timer"; interrupts = , @@ -823,8 +880,10 @@ <0x18325800 0x1400>; reg-names = "osm_l3_base", "osm_pwrcl_base", "osm_perfcl_base"; + l3-devs = <&cpu0_cpu_l3_lat &cpu6_cpu_l3_lat + &cdsp_cdsp_l3_lat>; + #clock-cells = <1>; - status = "disabled"; }; cpucc_debug: syscon@182a0018 { @@ -927,6 +986,12 @@ clock-frequency = <32768>; }; + aop-msg-client { + compatible = "qcom,debugfs-qmp-client"; + mboxes = <&qmp_aop 0>; + mbox-names = "aop"; + }; + qcom,msm-rtb { compatible = "qcom,msm-rtb"; qcom,rtb-size = <0x100000>; @@ -964,6 +1029,24 @@ status = "ok"; }; + bluetooth: bt_wcn3990 { + compatible = "qca,wcn3990"; + qca,bt-vdd-io-supply = <&pm6150_l10>; + qca,bt-vdd-core-supply = <&pm6150l_l2>; + qca,bt-vdd-pa-supply = <&pm6150l_l10>; + qca,bt-vdd-xtal-supply = <&pm6150l_l1>; + + qca,bt-vdd-io-voltage-level = <1700000 1900000>; /* IO */ + qca,bt-vdd-core-voltage-level = <1245000 1350000>; /* RFA */ + qca,bt-vdd-pa-voltage-level = <3200000 3400000>; /*chain0 */ + qca,bt-vdd-xtal-voltage-level = <1700000 1900000>; /* XO */ + + qca,bt-vdd-io-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-core-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-pa-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-xtal-current-level = <1>; /* LPM/PFM */ + }; + slim_aud: slim@62dc0000 { cell-index = <1>; compatible = "qcom,slim-ngd"; @@ -995,13 +1078,21 @@ reg-names = "slimbus_physical", "slimbus_bam_physical"; interrupts = <0 291 0>, <0 292 0>; interrupt-names = "slimbus_irq", "slimbus_bam_irq"; - status = "disabled"; + status = "ok"; qcom,iommu-s1-bypass; iommu_slim_qca_ctrl_cb: qcom,iommu_slim_ctrl_cb { compatible = "qcom,iommu-slim-ctrl-cb"; iommus = <&apps_smmu 0x1bf3 0x0>; }; + + /* Slimbus Slave DT for WCN3990 */ + btfmslim_codec: wcn3990 { + compatible = "qcom,btfmslim_slave"; + elemental-addr = [00 01 20 02 17 02]; + qcom,btfm-slim-ifd = "btfmslim_slave_ifd"; + qcom,btfm-slim-ifd-elemental-addr = [00 00 20 02 17 02]; + }; }; wdog: qcom,wdt@17c10000{ @@ -1371,9 +1462,9 @@ interrupts = <0 129 0>; #mbox-cells = <1>; qcom,drv-id = <0>; - qcom,tcs-config = , - , + qcom,tcs-config = , , + , ; }; @@ -1659,6 +1750,21 @@ qcom,glink-channels = "g_glink_audio_data"; qcom,intents = <0x1000 2>; }; + + qcom,diag_data { + qcom,glink-channels = "DIAG_DATA"; + qcom,intents = <0x4000 2>; + }; + + qcom,diag_ctrl { + qcom,glink-channels = "DIAG_CTRL"; + qcom,intents = <0x4000 1>; + }; + + qcom,diag_cmd { + qcom,glink-channels = "DIAG_CMD"; + qcom,intents = <0x4000 1 >; + }; }; }; @@ -1745,6 +1851,9 @@ qcom,smp2p_sleepstate { compatible = "qcom,smp2p-sleepstate"; qcom,smem-states = <&sleepstate_smp2p_out 0>; + interrupt-parent = <&sleepstate_smp2p_in>; + interrupts = <0 0>; + interrupt-names = "smp2p-sleepstate-in"; }; qcom,smp2p-modem { @@ -1765,6 +1874,18 @@ interrupt-controller; #interrupt-cells = <2>; }; + + smp2p_ipa_1_out: qcom,smp2p-ipa-1-out { + qcom,entry-name = "ipa"; + #qcom,smem-state-cells = <1>; + }; + + /* ipa - inbound entry from mss */ + smp2p_ipa_1_in: qcom,smp2p-ipa-1-in { + qcom,entry-name = "ipa"; + interrupt-controller; + #interrupt-cells = <2>; + }; }; qcom,smp2p-adsp { @@ -1790,6 +1911,12 @@ qcom,entry-name = "sleepstate"; #qcom,smem-state-cells = <1>; }; + + sleepstate_smp2p_in: qcom,sleepstate-in { + qcom,entry-name = "sleepstate_see"; + interrupt-controller; + #interrupt-cells = <2>; + }; }; qcom,smp2p-cdsp { @@ -1812,6 +1939,28 @@ }; }; + sdcc1_ice: sdcc1ice@7C8000 { + compatible = "qcom,ice"; + reg = <0x7C8000 0x8000>; + qcom,enable-ice-clk; + clock-names = "ice_core_clk_src", "ice_core_clk", + "bus_clk", "iface_clk"; + clocks = <&clock_gcc GCC_SDCC1_ICE_CORE_CLK_SRC>, + <&clock_gcc GCC_SDCC1_ICE_CORE_CLK>, + <&clock_gcc GCC_SDCC1_AHB_CLK>, + <&clock_gcc GCC_SDCC1_APPS_CLK>; + qcom,op-freq-hz = <300000000>, <0>, <0>, <0>; + qcom,msm-bus,name = "sdcc_ice_noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 757 0 0>, /* No vote */ + <1 757 1000 0>; /* Max. bandwidth */ + qcom,bus-vector-names = "MIN", + "MAX"; + qcom,instance-type = "sdcc"; + }; + sdhc_1: sdhci@7c4000 { compatible = "qcom,sdhci-msm-v5"; reg = <0x7c4000 0x1000>, <0x7c5000 0x1000>; @@ -1820,6 +1969,7 @@ interrupts = , ; interrupt-names = "hc_irq", "pwr_irq"; + sdhc-msm-crypto = <&sdcc1_ice>; qcom,bus-width = <8>; qcom,large-address-bus; @@ -1831,8 +1981,11 @@ qcom,devfreq,freq-table = <50000000 200000000>; clocks = <&clock_gcc GCC_SDCC1_AHB_CLK>, - <&clock_gcc GCC_SDCC1_APPS_CLK>; - clock-names = "iface_clk", "core_clk"; + <&clock_gcc GCC_SDCC1_APPS_CLK>, + <&clock_gcc GCC_SDCC1_ICE_CORE_CLK>; + clock-names = "iface_clk", "core_clk", "ice_core_clk"; + + qcom,ice-clk-rates = <300000000 75000000>; qcom,nonremovable; status = "disabled"; @@ -1902,6 +2055,29 @@ clock-names = "iface_clk"; }; + ufs_ice: ufsice@1d90000 { + compatible = "qcom,ice"; + reg = <0x1d90000 0x8000>; + qcom,enable-ice-clk; + clock-names = "ufs_core_clk", "bus_clk", + "iface_clk", "ice_core_clk"; + clocks = <&clock_gcc GCC_UFS_PHY_AXI_CLK>, + <&clock_gcc GCC_UFS_MEM_CLKREF_CLK>, + <&clock_gcc GCC_UFS_PHY_AHB_CLK>, + <&clock_gcc GCC_UFS_PHY_ICE_CORE_CLK>; + qcom,op-freq-hz = <0>, <0>, <0>, <300000000>; + vdd-hba-supply = <&ufs_phy_gdsc>; + qcom,msm-bus,name = "ufs_ice_noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 650 0 0>, /* No vote */ + <1 650 1000 0>; /* Max. bandwidth */ + qcom,bus-vector-names = "MIN", + "MAX"; + qcom,instance-type = "ufs"; + }; + ufsphy_mem: ufsphy_mem@1d87000 { reg = <0x1d87000 0xddc>; /* PHY regs */ reg-names = "phy_mem"; @@ -1925,6 +2101,7 @@ interrupts = <0 265 0>; phys = <&ufsphy_mem>; phy-names = "ufsphy"; + ufs-qcom-crypto = <&ufs_ice>; lanes-per-direction = <1>; dev-ref-clk-freq = <0>; /* 19.2 MHz */ @@ -2079,8 +2256,8 @@ <125 512 393600 393600>; qcom,smmu-s1-enable; qcom,no-clock-support; - iommus = <&apps_smmu 0x0106 0x0011>, - <&apps_smmu 0x0116 0x0011>; + iommus = <&apps_smmu 0x0506 0x0011>, + <&apps_smmu 0x0516 0x0011>; }; qcom_crypto: qcrypto@1de0000 { @@ -2109,8 +2286,8 @@ qcom,use-sw-hmac-algo; qcom,smmu-s1-enable; qcom,no-clock-support; - iommus = <&apps_smmu 0x0104 0x0011>, - <&apps_smmu 0x0114 0x0011>; + iommus = <&apps_smmu 0x0504 0x0011>, + <&apps_smmu 0x0514 0x0011>; }; qcom_tzlog: tz-log@146aa720 { @@ -2133,8 +2310,8 @@ interrupts = ; qcom,ee = <0>; qcom,channel = <0>; - #address-cells = <2>; - #size-cells = <0>; + #address-cells = <1>; + #size-cells = <1>; interrupt-controller; #interrupt-cells = <4>; cell-index = <0>; @@ -2291,12 +2468,402 @@ qcom,wlan-msa-fixed-region = <&wlan_msa_mem>; }; + qcom,msm_gsi { + compatible = "qcom,msm_gsi"; + }; + + qcom,rmnet-ipa { + compatible = "qcom,rmnet-ipa3"; + qcom,rmnet-ipa-ssr; + qcom,ipa-platform-type-msm; + qcom,ipa-advertise-sg-support; + qcom,ipa-napi-enable; + }; + + ipa_hw: qcom,ipa@1e00000 { + compatible = "qcom,ipa"; + reg = <0x1e00000 0x34000>, + <0x1e04000 0x2c000>; + reg-names = "ipa-base", "gsi-base"; + interrupts = <0 311 0>, <0 432 0>; + interrupt-names = "ipa-irq", "gsi-irq"; + qcom,ipa-hw-ver = <16>; /* IPA core version = IPAv4.2 */ + qcom,ipa-hw-mode = <0>; + qcom,ee = <0>; + qcom,use-ipa-tethering-bridge; + qcom,modem-cfg-emb-pipe-flt; + qcom,ipa-wdi2; + qcom,ipa-wdi2_over_gsi; + qcom,ipa-fltrt-not-hashable; + qcom,use-64-bit-dma-mask; + qcom,arm-smmu; + qcom,smmu-fast-map; + qcom,use-ipa-pm; + qcom,bandwidth-vote-for-ipa; + qcom,msm-bus,name = "ipa"; + qcom,msm-bus,num-cases = <5>; + qcom,msm-bus,num-paths = <4>; + qcom,msm-bus,vectors-KBps = + /* No vote */ + , + , + , + , + /* SVS2 */ + , + , + , + , + /* SVS */ + , + , + , + , + /* NOMINAL */ + , + , + , + , + /* TURBO */ + , + , + , + ; + qcom,bus-vector-names = + "MIN", "SVS2", "SVS", "NOMINAL", "TURBO"; + qcom,throughput-threshold = <310 600 1000>; + qcom,scaling-exceptions = <>; + + /* smp2p information */ + qcom,smp2p_map_ipa_1_out { + compatible = "qcom,smp2p-map-ipa-1-out"; + qcom,smem-states = <&smp2p_ipa_1_out 0>; + qcom,smem-state-names = "ipa-smp2p-out"; + }; + + qcom,smp2p_map_ipa_1_in { + compatible = "qcom,smp2p-map-ipa-1-in"; + interrupts-extended = <&smp2p_ipa_1_in 0 0>; + interrupt-names = "ipa-smp2p-in"; + }; + }; + + llcc_pmu: llcc-pmu@90cc000 { + compatible = "qcom,qcom-llcc-pmu"; + reg = <0x090cc000 0x300>; + reg-names = "lagg-base"; + }; + + llcc_bw_opp_table: llcc-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY( 300, 16); /* 4577 MB/s */ + BW_OPP_ENTRY( 466, 16); /* 7110 MB/s */ + BW_OPP_ENTRY( 600, 16); /* 9155 MB/s */ + BW_OPP_ENTRY( 806, 16); /* 12298 MB/s */ + BW_OPP_ENTRY( 933, 16); /* 14236 MB/s */ + }; + + cpu_cpu_llcc_bw: qcom,cpu-cpu-llcc-bw { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&llcc_bw_opp_table>; + }; + + cpu_cpu_llcc_bwmon: qcom,cpu-cpu-llcc-bwmon@90b6300 { + compatible = "qcom,bimc-bwmon4"; + reg = <0x90b6300 0x300>, <0x90b6200 0x200>; + reg-names = "base", "global_base"; + interrupts = ; + qcom,mport = <0>; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&cpu_cpu_llcc_bw>; + qcom,count-unit = <0x10000>; + }; + + ddr_bw_opp_table: ddr-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY( 200, 4); /* 762 MB/s */ + BW_OPP_ENTRY( 300, 4); /* 1144 MB/s */ + BW_OPP_ENTRY( 451, 4); /* 1720 MB/s */ + BW_OPP_ENTRY( 547, 4); /* 2086 MB/s */ + BW_OPP_ENTRY( 681, 4); /* 2597 MB/s */ + BW_OPP_ENTRY( 768, 4); /* 2929 MB/s */ + BW_OPP_ENTRY(1017, 4); /* 3879 MB/s */ + BW_OPP_ENTRY(1353, 4); /* 5161 MB/s */ + BW_OPP_ENTRY(1555, 4); /* 5931 MB/s */ + BW_OPP_ENTRY(1804, 4); /* 6881 MB/s */ + }; + + cpu_llcc_ddr_bw: qcom,cpu-llcc-ddr-bw { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu_llcc_ddr_bwmon: qcom,cpu-llcc-ddr-bwmon@90cd000 { + compatible = "qcom,bimc-bwmon5"; + reg = <0x90cd000 0x1000>; + reg-names = "base"; + interrupts = ; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&cpu_llcc_ddr_bw>; + qcom,count-unit = <0x10000>; + }; + + suspendable_ddr_bw_opp_table: suspendable-ddr-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY( 0, 4); /* 0 MB/s */ + BW_OPP_ENTRY( 200, 4); /* 762 MB/s */ + BW_OPP_ENTRY( 300, 4); /* 1144 MB/s */ + BW_OPP_ENTRY( 451, 4); /* 1720 MB/s */ + BW_OPP_ENTRY( 547, 4); /* 2086 MB/s */ + BW_OPP_ENTRY( 681, 4); /* 2597 MB/s */ + BW_OPP_ENTRY( 768, 4); /* 2929 MB/s */ + BW_OPP_ENTRY(1017, 4); /* 3879 MB/s */ + BW_OPP_ENTRY(1353, 4); /* 5161 MB/s */ + BW_OPP_ENTRY(1555, 4); /* 5931 MB/s */ + BW_OPP_ENTRY(1804, 4); /* 6881 MB/s */ + }; + + cdsp_cdsp_l3_lat: qcom,cdsp-cdsp-l3-lat { + compatible = "devfreq-simple-dev"; + clock-names = "devfreq_clk"; + clocks = <&clock_cpucc L3_MISC_VOTE_CLK>; + governor = "powersave"; + }; + + cpu0_cpu_l3_lat: qcom,cpu0-cpu-l3-lat { + compatible = "devfreq-simple-dev"; + clock-names = "devfreq_clk"; + clocks = <&clock_cpucc L3_CLUSTER0_VOTE_CLK>; + governor = "performance"; + }; + + cpu0_cpu_l3_latmon: qcom,cpu0-cpu-l3-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; + qcom,target-dev = <&cpu0_cpu_l3_lat>; + qcom,cachemiss-ev = <0x17>; + qcom,core-dev-table = + < 768000 300000000 >, + < 1017600 566800000 >, + < 1248000 768000000 >, + < 1497000 940800000 >, + < 1804800 1459200000 >; + }; + + cpu6_cpu_l3_lat: qcom,cpu6-cpu-l3-lat { + compatible = "devfreq-simple-dev"; + clock-names = "devfreq_clk"; + clocks = <&clock_cpucc L3_CLUSTER1_VOTE_CLK>; + governor = "performance"; + }; + + cpu6_cpu_l3_latmon: qcom,cpu6-cpu-l3-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU6 &CPU7>; + qcom,target-dev = <&cpu6_cpu_l3_lat>; + qcom,cachemiss-ev = <0x17>; + qcom,core-dev-table = + < 1094000 566800000 >, + < 1324000 768000000 >, + < 1708800 1190800000 >, + < 1939000 1382000000 >, + < 2438400 1459200000 >; + }; + + cpu0_cpu_llcc_lat: qcom,cpu0-cpu-llcc-lat { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&llcc_bw_opp_table>; + }; + + cpu0_cpu_llcc_latmon: qcom,cpu0-cpu-llcc-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; + qcom,target-dev = <&cpu0_cpu_llcc_lat>; + qcom,cachemiss-ev = <0x2A>; + qcom,core-dev-table = + < 1324000 MHZ_TO_MBPS(300, 16) >, + < 1497000 MHZ_TO_MBPS(466, 16) >, + < 1804800 MHZ_TO_MBPS(600, 16) >; + }; + + cpu6_cpu_llcc_lat: qcom,cpu6-cpu-llcc-lat { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&llcc_bw_opp_table>; + }; + + cpu6_cpu_llcc_latmon: qcom,cpu6-cpu-llcc-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU6 &CPU7>; + qcom,target-dev = <&cpu6_cpu_llcc_lat>; + qcom,cachemiss-ev = <0x2A>; + qcom,core-dev-table = + < 806000 MHZ_TO_MBPS(300, 16) >, + < 1094000 MHZ_TO_MBPS(466, 16) >, + < 1324000 MHZ_TO_MBPS(600, 16) >, + < 1708800 MHZ_TO_MBPS(806, 16) >, + < 2438400 MHZ_TO_MBPS(933, 16) >; + }; + + cpu0_llcc_ddr_lat: qcom,cpu0-llcc-ddr-lat { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu0_llcc_ddr_latmon: qcom,cpu0-llcc-ddr-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; + qcom,target-dev = <&cpu0_llcc_ddr_lat>; + qcom,cachemiss-ev = <0x1000>; + qcom,core-dev-table = + < 768000 MHZ_TO_MBPS( 300, 4) >, + < 1017600 MHZ_TO_MBPS( 451, 4) >, + < 1248000 MHZ_TO_MBPS( 547, 4) >, + < 1497000 MHZ_TO_MBPS( 768, 4) >, + < 1804800 MHZ_TO_MBPS(1017, 4) >; + }; + + cpu6_llcc_ddr_lat: qcom,cpu6-llcc-ddr-lat { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu6_llcc_ddr_latmon: qcom,cpu6-llcc-ddr-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU6 &CPU7>; + qcom,target-dev = <&cpu6_llcc_ddr_lat>; + qcom,cachemiss-ev = <0x1000>; + qcom,core-dev-table = + < 806000 MHZ_TO_MBPS( 451, 4) >, + < 1094000 MHZ_TO_MBPS( 547, 4) >, + < 1324000 MHZ_TO_MBPS(1017, 4) >, + < 1708800 MHZ_TO_MBPS(1555, 4) >, + < 2438400 MHZ_TO_MBPS(1804, 4) >; + }; + + cpu0_cpu_ddr_latfloor: qcom,cpu0-cpu-ddr-latfloor { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu0_computemon: qcom,cpu0-computemon { + compatible = "qcom,arm-cpu-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; + qcom,target-dev = <&cpu0_cpu_ddr_latfloor>; + qcom,core-dev-table = + < 768000 MHZ_TO_MBPS( 300, 4) >, + < 1248000 MHZ_TO_MBPS( 451, 4) >, + < 1497000 MHZ_TO_MBPS( 547, 4) >, + < 1804800 MHZ_TO_MBPS( 768,4) >; + }; + + cpu6_cpu_ddr_latfloor: qcom,cpu6-cpu-ddr-latfloor { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu6_computemon: qcom,cpu6-computemon { + compatible = "qcom,arm-cpu-mon"; + qcom,cpulist = <&CPU6 &CPU7>; + qcom,target-dev = <&cpu6_cpu_ddr_latfloor>; + qcom,core-dev-table = + < 1094000 MHZ_TO_MBPS( 300, 4) >, + < 1324000 MHZ_TO_MBPS( 547, 4) >, + < 1552200 MHZ_TO_MBPS( 768, 4) >, + < 1708000 MHZ_TO_MBPS(1017, 4) >, + < 2438400 MHZ_TO_MBPS(1804, 4) >; + }; + + npu_npu_ddr_bw: qcom,npu-npu-ddr-bw { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = ; + operating-points-v2 = <&suspendable_ddr_bw_opp_table>; + }; + + npu_npu_ddr_bwmon: qcom,npu-npu-ddr-bwmon@9960300 { + compatible = "qcom,bimc-bwmon4"; + reg = <0x9960300 0x300>, <0x9960200 0x200>; + reg-names = "base", "global_base"; + interrupts = ; + qcom,mport = <0>; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&npu_npu_ddr_bw>; + qcom,count-unit = <0x10000>; + }; + + ipa_smmu_ap: ipa_smmu_ap { + compatible = "qcom,ipa-smmu-ap-cb"; + qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x520 0x0>; + qcom,iova-mapping = <0x20000000 0x40000000>; + /* modem tables in IMEM */ + qcom,additional-mapping = <0x146bd000 0x146bd000 0x2000>; + }; + + ipa_smmu_wlan: ipa_smmu_wlan { + compatible = "qcom,ipa-smmu-wlan-cb"; + qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x521 0x0>; + /* ipa-uc ram */ + qcom,additional-mapping = <0x1e60000 0x1e60000 0x80000>; + }; + + ipa_smmu_uc: ipa_smmu_uc { + compatible = "qcom,ipa-smmu-uc-cb"; + qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x522 0x0>; + qcom,iova-mapping = <0x40400000 0x1fc00000>; + }; + + qcom,ipa_fws { + compatible = "qcom,pil-tz-generic"; + qcom,pas-id = <0xf>; + qcom,firmware-name = "ipa_fws"; + qcom,pil-force-shutdown; + memory-region = <&pil_ipa_fw_mem>; + }; + }; -#include "sdmmagpie-pinctrl.dtsi" #include "sdmmagpie-gdsc.dtsi" #include "sdmmagpie-bus.dtsi" #include "sdmmagpie-qupv3.dtsi" +#include "sdmmagpie-vidc.dtsi" +#include "sdmmagpie-sde-pll.dtsi" +#include "sdmmagpie-sde.dtsi" +#include "sdmmagpie-camera.dtsi" &pcie_0_gdsc { status = "ok"; @@ -2343,30 +2910,47 @@ }; &bps_gdsc { + clock-names = "ahb_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; + qcom,support-hw-trigger; status = "ok"; }; &ife_0_gdsc { + clock-names = "ahb_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; status = "ok"; }; &ife_1_gdsc { + clock-names = "ahb_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; status = "ok"; }; &ipe_0_gdsc { + clock-names = "ahb_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; + qcom,support-hw-trigger; status = "ok"; }; &ipe_1_gdsc { + clock-names = "ahb_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; + qcom,support-hw-trigger; status = "ok"; }; &titan_top_gdsc { + clock-names = "ahb_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; status = "ok"; }; &mdss_core_gdsc { + clock-names = "ahb_clk"; + clocks = <&clock_gcc GCC_DISP_AHB_CLK>; status = "ok"; }; @@ -2415,6 +2999,7 @@ #include "sdmmagpie-pm.dtsi" #include "pm6150.dtsi" #include "pm6150l.dtsi" +#include "sdmmagpie-pinctrl.dtsi" #include "pm8009.dtsi" #include "sdmmagpie-regulator.dtsi" #include "sdmmagpie-camera.dtsi" @@ -2422,10 +3007,27 @@ #include "sdmmagpie-usb.dtsi" #include "sdmmagpie-thermal.dtsi" +&qupv3_se9_i2c { + status = "ok"; + fsa4480: fsa4480@43 { + compatible = "qcom,fsa4480-i2c"; + reg = <0x43>; + pinctrl-names = "default"; + pinctrl-0 = <&fsa_usbc_ana_en>; + }; +}; + +#include "sdmmagpie-audio.dtsi" + &usb0 { extcon = <&pm6150_pdphy>, <&pm6150_charger>, <&eud>; }; +&pm6150_charger { + dpdm-supply = <&qusb_phy0>; + qcom,suspend-input-on-debug-batt; +}; + &pm6150_vadc { rf_pa0_therm { reg = ; @@ -2450,6 +3052,15 @@ qcom,hw-settle-time = <200>; qcom,pre-scaling = <1 1>; }; + + snoc_cnoc_keepalive: qcom,snoc_cnoc_keepalive { + compatible = "qcom,devbw"; + governor = "powersave"; + qcom,src-dst-ports = <161 627>; + qcom,active-only; + status = "ok"; + qcom,bw-tbl = < 1 >; + }; }; &pm6150_adc_tm { @@ -2485,6 +3096,9 @@ }; &pm6150l_vadc { + pinctrl-names = "default"; + pinctrl-0 = <&nvm_therm_default>; + conn_therm { reg = ; label = "conn_therm"; @@ -2517,6 +3131,15 @@ }; }; +&pm6150l_gpios { + nvm_therm { + nvm_therm_default: nvm_therm_default { + pins = "gpio10"; + bias-high-impedance; + }; + }; +}; + &pm6150l_adc_tm { io-channels = <&pm6150l_vadc ADC_AMUX_THM1_PU2>, <&pm6150l_vadc ADC_AMUX_THM3_PU2>, diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-pinctrl.dtsi index 04766c9aa5d339308908a5ce8034587529ac374b..44352691a0be5b3ff5fa39ba27c03c8c2ae7a317 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-pinctrl.dtsi @@ -13,7 +13,8 @@ &soc { tlmm: pinctrl@3000000 { compatible = "qcom,sdmshrike-pinctrl"; - reg = <0x03000000 0xdd2000>; + reg = <0x03000000 0xdd2000>, <0x17c000f0 0x60>; + reg-names = "pinctrl", "spi_cfg"; interrupts = <0 208 0>; gpio-controller; #gpio-cells = <2>; diff --git a/arch/arm64/boot/dts/qcom/sdx50m-external-soc.dtsi b/arch/arm64/boot/dts/qcom/sdx5xm-external-soc.dtsi similarity index 61% rename from arch/arm64/boot/dts/qcom/sdx50m-external-soc.dtsi rename to arch/arm64/boot/dts/qcom/sdx5xm-external-soc.dtsi index a7752caede0f8b348aab2d4a9516ee3bc4817a3f..0d0af328d7889bb4bbfe3b5ef3312a176a5bf994 100644 --- a/arch/arm64/boot/dts/qcom/sdx50m-external-soc.dtsi +++ b/arch/arm64/boot/dts/qcom/sdx5xm-external-soc.dtsi @@ -12,7 +12,6 @@ &soc { mdm3: qcom,mdm3 { - compatible = "qcom,ext-sdx50m"; cell-index = <0>; #address-cells = <0>; interrupt-parent = <&mdm3>; @@ -32,7 +31,29 @@ qcom,ssctl-instance-id = <0x10>; qcom,support-shutdown; qcom,pil-force-shutdown; + pinctrl-names = "default", "mdm_active", "mdm_suspend"; + pinctrl-0 = <&ap2mdm_pon_reset_default>; + pinctrl-1 = <&ap2mdm_active &mdm2ap_active>; + pinctrl-2 = <&ap2mdm_sleep &mdm2ap_sleep>; + interrupt-map = <0 &tlmm 53 0x3 + 1 &tlmm 135 0x3>; + qcom,mdm2ap-errfatal-gpio = <&tlmm 53 0x00>; + qcom,ap2mdm-errfatal-gpio = <&tlmm 141 0x00>; + qcom,mdm2ap-status-gpio = <&tlmm 142 0x00>; + qcom,ap2mdm-status-gpio = <&tlmm 135 0x00>; + qcom,ap2mdm-soft-reset-gpio = <&pm8150l_gpios 9 0>; qcom,esoc-skip-restart-for-mdm-crash; - status = "disabled"; + status = "ok"; + }; +}; + +&pm8150l_gpios { + ap2mdm_pon_reset { + ap2mdm_pon_reset_default: ap2mdm_pon_reset_default { + /* MDM PON conrol*/ + pins = "gpio9"; + function = "normal"; + power-source = <1>; /* 1.8V */ + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-pinctrl.dtsi index ab6e1c7a99cb8994d0bbe55a7380733f499910e0..40d022230e8c9cb602deb7769ad5f82951db7246 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie-pinctrl.dtsi @@ -15,11 +15,12 @@ compatible = "qcom,sdxprairie-pinctrl"; reg = <0xf100000 0x300000>, <0xb204900 0x280>; + reg-names = "pinctrl", "pdc"; interrupts = ; gpio-controller; #gpio-cells = <2>; interrupt-controller; - interrupt-parent = <&intc>; + interrupt-parent = <&pdc>; #interrupt-cells = <2>; uart3_console_active: uart3_console_active { diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-pm.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-pm.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..bcd1216388a7a48d262376eea43eb6b8e78ba175 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdxprairie-pm.dtsi @@ -0,0 +1,101 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + qcom,lpm-levels { + compatible = "qcom,lpm-levels"; + #address-cells = <1>; + #size-cells = <0>; + + qcom,pm-cluster@0{ + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + label = "system"; + qcom,psci-mode-shift = <0>; + qcom,psci-mode-mask = <0xf>; + + qcom,pm-cluster-level@0 { + reg = <0>; + label = "cx_active"; + qcom,psci-mode = <0x0>; + qcom,entry-latency-us = <120>; + qcom,exit-latency-us = <150>; + qcom,min-residency-us = <6488>; + }; + + qcom,pm-cluster-level@1 { + reg = <1>; + label = "cx_min"; + qcom,psci-mode = <0x4>; + qcom,entry-latency-us = <140>; + qcom,exit-latency-us = <200>; + qcom,min-residency-us = <8000>; + qcom,min-child-idx = <2>; + qcom,notify-rpm; + qcom,is-reset; + }; + + qcom,pm-cpu@0 { + #address-cells = <1>; + #size-cells = <0>; + qcom,psci-mode-shift = <0>; + qcom,psci-mode-mask = <0xf>; + qcom,cpu = <&CPU0>; + + qcom,pm-cpu-level@0{ + reg = <0>; + label = "wfi"; + qcom,psci-cpu-mode = <0x1>; + qcom,latency-us = <1>; + qcom,entry-latency-us = <57>; + qcom,exit-latency-us = <43>; + qcom,min-residency-us = <83>; + }; + + qcom,pm-cpu-level@1 { + reg = <1>; + label ="standalone_pc"; + qcom,psci-cpu-mode = <0x4>; + qcom,entry-latency-us = <120>; + qcom,exit-latency-us = <120>; + qcom,min-residency-us = <4488>; + qcom,use-broadcast-timer; + qcom,is-reset; + }; + + qcom,pm-cpu-level@2 { + reg = <2>; + label = "system-pc"; + qcom,psci-cpu-mode = <0x4>; + qcom,entry-latency-us = <120>; + qcom,exit-latency-us = <150>; + qcom,min-residency-us = <6488>; + qcom,use-broadcast-timer; + qcom,is-reset; + }; + }; + }; + }; + + qcom,rpm-stats@c300000 { + compatible = "qcom,rpm-stats"; + reg = <0xC300000 0x1000>, <0xC370004 0x4>; + reg-names = "phys_addr_base", "offset_addr"; + qcom,num-records = <3>; + }; + + qcom,rpmh-master-stats@b211200 { + compatible = "qcom,rpmh-master-stats-v1"; + reg = <0xb211200 0x60>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-regulator.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ba09309adbcf343adfc0a43e561c1a7c6590ace2 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdxprairie-regulator.dtsi @@ -0,0 +1,195 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +&soc { + /* Stub regulators */ + + /* PMXPRAIRIE S1 + S6 = VDD_MODEM supply */ + VDD_MODEM_LEVEL: S1E_LEVEL: + pmxprairie_s1_level: regulator-pmxprairie-s1-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxprairie_s1_level"; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + S2E: pmxprairie_s2: regulator-pmxprairie-s2 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxprairie_s2"; + regulator-min-microvolt = <1224000>; + regulator-max-microvolt = <1400000>; + }; + + S3E: pmxprairie_s3: regulator-pmxprairie-s3 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxprairie_s3"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1000000>; + }; + + S4E: pmxprairie_s4: regulator-pmxprairie-s4 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxprairie_s4"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1956000>; + }; + + /* PMXPRAIRIE S5 = VDD_CX supply */ + VDD_CX_LEVEL_AO: S5E_LEVEL_AO: pmxprairie_s5_level_ao: + VDD_CX_LEVEL: S5E_LEVEL: + pmxprairie_s5_level: regulator-pmxprairie-s5-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxprairie_s5_level"; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + /* PMXPRAIRIE S7 = VDD_MX supply */ + VDD_MX_LEVEL_AO: S7E_LEVEL_AO: pmxprairie_s7_level_ao: + VDD_MX_LEVEL: S7E_LEVEL: + pmxprairie_s7_level: regulator-pmxprairie-s7-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxprairie_s7_level"; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + L1E: pmxprairie_l1: regulator-pmxprairie-l1 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxprairie_l1"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + qcom,hpm-min-load = <30000>; + }; + + L2E: pmxprairie_l2: regulator-pmxprairie-l2 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxprairie_l2"; + regulator-min-microvolt = <1128000>; + regulator-max-microvolt = <1128000>; + qcom,hpm-min-load = <30000>; + }; + + L3E: pmxprairie_l3: regulator-pmxprairie-l3 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxprairie_l3"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + qcom,hpm-min-load = <30000>; + }; + + L4E: pmxprairie_l4: regulator-pmxprairie-l4 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxprairie_l4"; + regulator-min-microvolt = <872000>; + regulator-max-microvolt = <872000>; + qcom,hpm-min-load = <30000>; + }; + + L5E: pmxprairie_l5: regulator-pmxprairie-l5 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxprairie_l5"; + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <1704000>; + qcom,hpm-min-load = <10000>; + }; + + L6E: pmxprairie_l6: regulator-pmxprairie-l6 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxprairie_l6"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,hpm-min-load = <10000>; + }; + + L7E: pmxprairie_l7: regulator-pmxprairie-l7 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxprairie_l7"; + regulator-min-microvolt = <480000>; + regulator-max-microvolt = <900000>; + qcom,hpm-min-load = <30000>; + }; + + L8E: pmxprairie_l8: regulator-pmxprairie-l8 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxprairie_l8"; + regulator-min-microvolt = <480000>; + regulator-max-microvolt = <900000>; + qcom,hpm-min-load = <30000>; + }; + + L9E: pmxprairie_l9: regulator-pmxprairie-l9 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxprairie_l9"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + qcom,hpm-min-load = <30000>; + }; + + L10E: pmxprairie_l10: regulator-pmxprairie-l10 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxprairie_l10"; + regulator-min-microvolt = <3088000>; + regulator-max-microvolt = <3088000>; + qcom,hpm-min-load = <10000>; + }; + + L11E: pmxprairie_l11: regulator-pmxprairie-l11 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxprairie_l11"; + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <3000000>; + qcom,hpm-min-load = <10000>; + }; + + L12E: pmxprairie_l12: regulator-pmxprairie-l12 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxprairie_l12"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + qcom,hpm-min-load = <30000>; + }; + + L13E: pmxprairie_l13: regulator-pmxprairie-l13 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxprairie_l13"; + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <3000000>; + qcom,hpm-min-load = <10000>; + }; + + L14E: pmxprairie_l14: regulator-pmxprairie-l14 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxprairie_l14"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <800000>; + qcom,hpm-min-load = <30000>; + }; + + L15E: pmxprairie_l15: regulator-pmxprairie-l15 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxprairie_l15"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + qcom,hpm-min-load = <30000>; + }; + + L16E: pmxprairie_l16: regulator-pmxprairie-l16 { + compatible = "qcom,stub-regulator"; + regulator-name = "pmxprairie_l16"; + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <1904000>; + qcom,hpm-min-load = <10000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi index 6f7c993c1c0878749ef7841684632f9adc9e465b..9a1d0c5e3a08fb8166eccb280a64f505a6335872 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi @@ -16,22 +16,35 @@ #include #include #include +#include / { model = "Qualcomm Technologies, Inc. SDXPRAIRIE"; compatible = "qcom,sdxprairie"; qcom,msm-id = <357 0x0>; - interrupt-parent = <&intc>; + interrupt-parent = <&pdc>; reserved-memory { #address-cells = <1>; #size-cells = <1>; ranges; + tz_mem: tz_region@8ff00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x8ff00000 0x100000>; + label = "tz_mem"; + }; + + smem_region: smem_region@8fe40000 { + no-map; + reg = <0x8fe40000 0xc0000>; + }; + peripheral2_mem: peripheral2_region@8fd00000 { compatible = "removed-dma-pool"; no-map; - reg = <0x8fd00000 0x300000>; + reg = <0x8fd00000 0x140000>; label = "peripheral2_mem"; }; @@ -63,6 +76,7 @@ soc: soc { }; }; +#include "sdxprairie-regulator.dtsi" &soc { #address-cells = <1>; @@ -72,11 +86,20 @@ intc: interrupt-controller@17800000 { compatible = "qcom,msm-qgic2"; interrupt-controller; + interrupt-parent = <&intc>; #interrupt-cells = <3>; reg = <0x17800000 0x1000>, <0x17802000 0x1000>; }; + pdc: interrupt-controller@b210000{ + compatible = "qcom,pdc-sdxprairie"; + reg = <0xb210000 0x30000>; + #interrupt-cells = <3>; + interrupt-parent = <&intc>; + interrupt-controller; + }; + timer { compatible = "arm,armv7-timer"; interrupts = <1 13 0xf08>, @@ -201,6 +224,18 @@ qcom,rmnet-ipa-ssr; }; + qcom,ipa_fws { + compatible = "qcom,pil-tz-generic"; + qcom,pas-id = <0xf>; + qcom,firmware-name = "ipa_fws"; + qcom,pil-force-shutdown; + }; + + qcom,sps { + compatible = "qcom,msm-sps-4k"; + qcom,pipe-attr-ee; + }; + ipa_hw: qcom,ipa@01e00000 { compatible = "qcom,ipa"; reg = <0x1e00000 0xc0000>, @@ -252,8 +287,148 @@ qcom,throughput-threshold = <310 600 1000>; qcom,scaling-exceptions = <>; }; + + tcsr_mutex_block: syscon@1f40000 { + compatible = "syscon"; + reg = <0x1f40000 0x20000>; + }; + + tcsr_mutex: hwlock { + compatible = "qcom,tcsr-mutex"; + syscon = <&tcsr_mutex_block 0 0x1000>; + #hwlock-cells = <1>; + }; + + smem: qcom,smem { + compatible = "qcom,smem"; + memory-region = <&smem_region>; + hwlocks = <&tcsr_mutex 3>; + }; + + apcs_glb: mailbox@0x17811000 { + compatible = "qcom,sdxprairie-apcs-gcc"; + reg = <0x17811000 0xb9>; + #mbox-cells = <1>; + }; + + qcom,glink { + compatible = "qcom,glink"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + glink_modem: modem { + qcom,remote-pid = <1>; + transport = "smem"; + mboxes = <&apcs_glb 12>; + mbox-names = "mpss_smem"; + interrupts = ; + + label = "modem"; + qcom,glink-label = "mpss"; + + qcom,modem_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + }; + }; + + qcom,glinkpkt { + compatible = "qcom,glinkpkt"; + + qcom,glinkpkt-at-mdm0 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DS"; + qcom,glinkpkt-dev-name = "at_mdm0"; + }; + + qcom,glinkpkt-data40-cntl { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA40_CNTL"; + qcom,glinkpkt-dev-name = "smdcntl8"; + }; + + qcom,glinkpkt-data1 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA1"; + qcom,glinkpkt-dev-name = "smd7"; + }; + + qcom,glinkpkt-data4 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA4"; + qcom,glinkpkt-dev-name = "smd8"; + }; + + qcom,glinkpkt-data11 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA11"; + qcom,glinkpkt-dev-name = "smd11"; + }; + }; + + qmp_aop: qcom,qmp-aop@c300000 { + compatible = "qcom,qmp-mbox"; + reg = <0xc310000 0x1000>, <0x17811008 0x4>; + reg-names = "msgram", "irq-reg-base"; + qcom,irq-mask = <0x1>; + interrupts = ; + + label = "aop"; + qcom,early-boot; + priority = <0>; + mbox-desc-offset = <0x0>; + #mbox-cells = <1>; + }; + + apps_rsc: mailbox@17840000 { + compatible = "qcom,tcs-drv"; + label = "apps_rsc"; + reg = <0x17840000 0x100>, <0x17840d00 0x3000>; + interrupts = <0 17 0>; + #mbox-cells = <1>; + qcom,drv-id = <1>; + qcom,tcs-config = , + , + , + ; + }; + + cmd_db: qcom,cmd-db@c37000c { + compatible = "qcom,cmd-db"; + reg = <0xc37000c 8>; + }; + + system_pm { + compatible = "qcom,system-pm"; + mboxes = <&apps_rsc 0>; + }; + + qcom,smp2p-modem@1799000c { + compatible = "qcom,smp2p"; + qcom,smem = <435>, <428>; + interrupts = ; + mboxes = <&apcs_glb 14>; + qcom,local-pid = <0>; + qcom,remote-pid = <1>; + + modem_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + modem_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; }; +#include "sdxprairie-pm.dtsi" #include "sdxprairie-pinctrl.dtsi" #include "sdxprairie-ion.dtsi" #include "sdxprairie-bus.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi index 007d7d1a3bab96e2eb0d2fc750d0cec39b3493c8..d8f72d86318b150bcd105f231637d1b02ba14286 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-audio-overlay.dtsi @@ -181,8 +181,8 @@ qcom,cdc-static-supplies = "cdc-vdd-ldo-rxtx", "cdc-vddpx-1", - "cdc-vdd-buck", "cdc-vdd-mic-bias"; + qcom,cdc-on-demand-supplies = "cdc-vdd-buck"; }; }; diff --git a/arch/arm64/boot/dts/qcom/sm6150-audio.dtsi b/arch/arm64/boot/dts/qcom/sm6150-audio.dtsi index 3597b81d2608c989bb927ea8a2703b499dcb5cb9..3ba096bcfeb31625ebc9a0bff89151a0d56a04ae 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-audio.dtsi @@ -134,6 +134,7 @@ "msm-dai-cdc-dma-dev.45115", "msm-dai-cdc-dma-dev.45116", "msm-dai-cdc-dma-dev.45118"; + fsa4480-i2c-handle = <&fsa4480>; }; }; @@ -145,13 +146,3 @@ elemental-addr = [ff ff ff fe 17 02]; }; }; - -&qupv3_se3_i2c { - status = "ok"; - fsa4480: fsa4480@43 { - compatible = "qcom,fsa4480-i2c"; - reg = <0x43>; - pinctrl-names = "default"; - pinctrl-0 = <&fsa_usbc_ana_en>; - }; -}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-bus.dtsi b/arch/arm64/boot/dts/qcom/sm6150-bus.dtsi index 06262c3108166c001229a0ed293f5d788b4bc0ba..cc73771442d125f146f49f7293945a70066f3ca8 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-bus.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-bus.dtsi @@ -316,7 +316,6 @@ qcom,qos-off = <4096>; qcom,base-offset = <16384>; qcom,sbm-offset = <0>; - qcom,bypass-qos-prg; qcom,bus-type = <1>; clocks = <>; }; @@ -367,7 +366,6 @@ qcom,qos-off = <128>; qcom,base-offset = <176128>; qcom,sbm-offset = <0>; - qcom,bypass-qos-prg; qcom,bus-type = <1>; clocks = <>; }; @@ -404,7 +402,6 @@ qcom,qos-off = <4096>; qcom,base-offset = <36864>; qcom,sbm-offset = <0>; - qcom,bypass-qos-prg; qcom,bus-type = <1>; clocks = <>; }; @@ -418,7 +415,6 @@ qcom,base-offset = <45056>; qcom,sbm-offset = <0>; qcom,bus-type = <1>; - qcom,bypass-qos-prg; clocks = <>; }; @@ -488,7 +484,7 @@ label = "mas-qhm-qspi"; qcom,buswidth = <4>; qcom,agg-ports = <1>; - qcom,qport = <19>; + qcom,qport = <18>; qcom,connections = <&slv_qns_a1noc_snoc>; qcom,bus-dev = <&fab_aggre1_noc>; qcom,bcms = <&bcm_cn1>; @@ -658,7 +654,7 @@ clocks = <&clock_gcc GCC_AGGRE_USB2_SEC_AXI_CLK>; clock-names = - "clk-usb3-sec-axi-no-rate"; + "clk-aggre-usb2-sec-axi-no-rate"; }; }; @@ -676,7 +672,7 @@ clocks = <&clock_gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>; clock-names = - "clk-usb3-sec-axi-no-rate"; + "clk-aggre-usb3-prim-axi-no-rate"; }; }; diff --git a/arch/arm64/boot/dts/qcom/sm6150-camera-sensor-adp.dtsi b/arch/arm64/boot/dts/qcom/sm6150-camera-sensor-adp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..30153ed84ec4052a08f3cf486dbf39008db8f9fa --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm6150-camera-sensor-adp.dtsi @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&cam_cci { + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; + + qcom,cam-sensor@0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + reg = <0x0>; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + + + cam_vio-supply = <&pm6155_1_s4>; + cam_vana-supply = <&pm6155_1_s4>; + cam_vdig-supply = <&pm6155_1_s4>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + + gpios = <&tlmm 43 0>, + <&tlmm 28 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x1>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + + cam_vio-supply = <&pm6155_1_s4>; + cam_vana-supply = <&pm6155_1_s4>; + cam_vdig-supply = <&pm6155_1_s4>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + + gpios = <&tlmm 31 0>, + <&tlmm 29 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + reg = <0x02>; + csiphy-sd-index = <2>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + + cam_vio-supply = <&pm6155_1_s4>; + cam_vana-supply = <&pm6155_1_s4>; + cam_vdig-supply = <&pm6155_1_s4>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + gpios = <&tlmm 31 0>, + <&tlmm 30 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi b/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi index be03427c5ba02cb1217a5d42e152796299813fe1..49e99bfdee8a13925ee3fda18b6f120a4307c997 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-coresight.dtsi @@ -520,10 +520,10 @@ port@1 { reg = <0>; - funnel_monaq_in_tpdm_dl_monaq: endpoint { + funnel_monaq_in_tpdm_monaq: endpoint { slave-mode; remote-endpoint = - <&tpdm_dl_monaq_out_funnel_monaq>; + <&tpdm_monaq_out_funnel_monaq>; }; }; }; @@ -703,21 +703,21 @@ }; }; - tpdm_dl_monaq: tpdm@69c0000 { + tpdm_monaq: tpdm@69c0000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b968>; reg = <0x69c0000 0x1000>; reg-names = "tpdm-base"; - coresight-name = "coresight-tpdm-dl-monaq"; + coresight-name = "coresight-tpdm-monaq"; clocks = <&clock_aop QDSS_CLK>; clock-names = "apb_pclk"; port { - tpdm_dl_monaq_out_funnel_monaq: endpoint { + tpdm_monaq_out_funnel_monaq: endpoint { remote-endpoint = - <&funnel_monaq_in_tpdm_dl_monaq>; + <&funnel_monaq_in_tpdm_monaq>; }; }; }; @@ -910,6 +910,7 @@ coresight-name = "coresight-tpdm-dcc"; + status = "disabled"; clocks = <&clock_aop QDSS_CLK>; clock-names = "apb_pclk"; @@ -1171,15 +1172,6 @@ }; port@1 { - reg = <5>; - funnel_swao_in_funnel_ssc: endpoint { - slave-mode; - remote-endpoint= - <&funnel_ssc_out_funnel_swao>; - }; - }; - - port@2 { reg = <6>; funnel_swao_in_replicator1_out: endpoint { slave-mode; @@ -1187,7 +1179,8 @@ <&replicator1_out_funnel_swao>; }; }; - port@3 { + + port@2 { reg = <7>; funnel_swao_in_tpda_swao: endpoint { slave-mode; @@ -1198,82 +1191,6 @@ }; }; - funnel_ssc: funnel@6b14000 { - compatible = "arm,primecell"; - arm,primecell-periphid = <0x0003b908>; - - reg = <0x6b14000 0x1000>; - reg-names = "funnel-base"; - - coresight-name = "coresight-funnel-ssc"; - - clocks = <&clock_aop QDSS_CLK>; - clock-names = "apb_pclk"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - funnel_ssc_out_funnel_swao: endpoint { - remote-endpoint = - <&funnel_swao_in_funnel_ssc>; - }; - }; - - port@1 { - reg = <0>; - funnel_ssc_in_ssc_etm0: endpoint { - slave-mode; - remote-endpoint = - <&ssc_etm0_out_funnel_ssc>; - }; - }; - - port@2 { - reg = <0>; - funnel_ssc_in_ssc_stm: endpoint { - slave-mode; - remote-endpoint = - <&ssc_stm_out_funnel_ssc>; - }; - }; - }; - }; - - ssc_stm: stm@6b13000 { - compatible = "arm,primecell"; - arm,primecell-periphid = <0x0003b962>; - - reg = <0x06b13000 0x1000>; - reg-names = "stm-base"; - coresight-name = "coresight-ssc-stm"; - - clocks = <&clock_aop QDSS_CLK>; - clock-names = "apb_pclk"; - - port { - ssc_stm_out_funnel_ssc: endpoint { - remote-endpoint = <&funnel_ssc_in_ssc_stm>; - }; - }; - }; - - ssc_etm0 { - compatible = "qcom,coresight-remote-etm"; - - coresight-name = "coresight-ssc-etm0"; - qcom,inst-id = <8>; - - port { - ssc_etm0_out_funnel_ssc: endpoint { - remote-endpoint = - <&funnel_ssc_in_ssc_etm0>; - }; - }; - }; - tpda_swao: tpda@6b01000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b969>; diff --git a/arch/arm64/boot/dts/qcom/sm6150-gpu.dtsi b/arch/arm64/boot/dts/qcom/sm6150-gpu.dtsi index 27d2f3a805e42d185ccb1c1ed47de0914ae3bdf9..f01c5e92f0189f5343ed3e3c3574b87a2d668c31 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-gpu.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-gpu.dtsi @@ -65,12 +65,10 @@ <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>, <&clock_gpucc GPU_CC_AHB_CLK>, <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>, - <&clock_gcc GCC_GPU_SNOC_DVM_GFX_CLK>, <&clock_gpucc GPU_CC_CX_GMU_CLK>; clock-names = "core_clk", "rbbmtimer_clk", "mem_clk", - "iface_clk", "mem_iface_clk", - "alt_mem_iface_clk", "gmu_clk"; + "iface_clk", "mem_iface_clk", "gmu_clk"; /* Bus Scale Settings */ qcom,gpubw-dev = <&gpubw>; @@ -167,7 +165,7 @@ qcom,initial-pwrlevel = <5>; qcom,ca-target-pwrlevel = <3>; - /* SVS_L1 */ + /* TURBO */ qcom,gpu-pwrlevel@0 { reg = <0>; qcom,gpu-freq = <845000000>; @@ -240,7 +238,7 @@ qcom,initial-pwrlevel = <5>; qcom,ca-target-pwrlevel = <3>; - /* SVS_L1 */ + /* TURBO */ qcom,gpu-pwrlevel@0 { reg = <0>; qcom,gpu-freq = <845000000>; @@ -313,6 +311,7 @@ qcom,initial-pwrlevel = <6>; qcom,ca-target-pwrlevel = <4>; + /* TURBO L1 */ qcom,gpu-pwrlevel@0 { reg = <0>; qcom,gpu-freq = <895000000>; @@ -320,7 +319,7 @@ qcom,bus-min = <10>; qcom,bus-max = <11>; }; - /* SVS_L1 */ + /* TURBO */ qcom,gpu-pwrlevel@1 { reg = <1>; qcom,gpu-freq = <845000000>; @@ -383,6 +382,70 @@ qcom,bus-max = <0>; }; }; + + qcom,gpu-pwrlevels-3 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <156>; + + qcom,initial-pwrlevel = <4>; + qcom,ca-target-pwrlevel = <2>; + + /* NOM L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <745000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <700000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + /* SVS L1 */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <550000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <9>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <435000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <290000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <4>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; }; }; @@ -392,13 +455,10 @@ reg = <0x050a0000 0x10000>; qcom,protect = <0xa0000 0x10000>; - clocks =<&clock_gcc GCC_GPU_CFG_AHB_CLK>, - <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>, - <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>, - <&clock_gcc GCC_GPU_SNOC_DVM_GFX_CLK>; + clocks =<&clock_gcc GCC_DDRSS_GPU_AXI_CLK>, + <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>; - clock-names = "iface_clk", "mem_clk", "mem_iface_clk", - "alt_mem_iface_clk"; + clock-names = "mem_clk", "mem_iface_clk"; qcom,secure_align_mask = <0xfff>; qcom,retention; @@ -416,4 +476,29 @@ iommus = <&kgsl_smmu 0x2 0x400>; }; }; + + rgmu: qcom,rgmu@0x0506d000 { + label = "kgsl-rgmu"; + compatible = "qcom,gpu-rgmu"; + + reg = <0x506d000 0x31000>; + reg-names = "kgsl_rgmu"; + + interrupts = <0 304 0>, <0 305 0>; + interrupt-names = "kgsl_oob", "kgsl_rgmu"; + + regulator-names = "vddcx", "vdd"; + vddcx-supply = <&gpu_cx_gdsc>; + vdd-supply = <&gpu_gx_gdsc>; + + clocks = <&clock_gpucc GPU_CC_CX_GMU_CLK>, + <&clock_gpucc GPU_CC_CXO_CLK>, + <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>, + <&clock_gpucc GPU_CC_AHB_CLK>, + <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&clock_gpucc GPU_CC_GX_GFX3D_CLK>; + + clock-names = "gmu", "rbbmtimer", "mem", + "iface", "mem_iface", "core"; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi index d3532c0aed6239d8265a1d0c377b2570600d9986..86b2ec4d310280b1851e438b5c03bb1ee25f1e05 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-idp.dtsi @@ -65,6 +65,7 @@ &pm6150l_wled { qcom,string-cfg= <3>; + qcom,leds-per-string = <7>; status = "ok"; }; @@ -188,12 +189,16 @@ <&pm6150_vadc ADC_USB_IN_I>, <&pm6150_vadc ADC_CHG_TEMP>, <&pm6150_vadc ADC_DIE_TEMP>, - <&pm6150_vadc ADC_AMUX_THM4_PU2>; + <&pm6150_vadc ADC_AMUX_THM4_PU2>, + <&pm6150_vadc ADC_SBUx>, + <&pm6150_vadc ADC_VPH_PWR>; io-channel-names = "usb_in_voltage", "usb_in_current", "chg_temp", "die_temp", - "conn_temp"; + "conn_temp", + "sbux_res", + "vph_voltage"; qcom,battery-data = <&mtp_batterydata>; qcom,step-charging-enable; qcom,sw-jeita-enable; diff --git a/arch/arm64/boot/dts/qcom/sm6150-ion.dtsi b/arch/arm64/boot/dts/qcom/sm6150-ion.dtsi index 3b6a61be4fabcfe41bc165dd58e692bf19a59faa..a9010fdb6b0db1296f1345e7fda8ace74cae5583 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-ion.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-ion.dtsi @@ -45,6 +45,15 @@ qcom,ion-heap-type = "HYP_CMA"; }; + qcom,ion-heap@14 { /* SECURE CARVEOUT HEAP */ + reg = <14>; + qcom,ion-heap-type = "SECURE_CARVEOUT"; + cdsp { + memory-region = <&cdsp_sec_mem>; + token = <0x20000000>; + }; + }; + qcom,ion-heap@9 { reg = <9>; qcom,ion-heap-type = "SYSTEM_SECURE"; diff --git a/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi index f623b4fc150be99e0973f8970e94f709163848c4..6154025b5c38a4811ee05855333f97c1a056742a 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-pinctrl.dtsi @@ -15,7 +15,8 @@ &soc { tlmm: pinctrl@03000000 { compatible = "qcom,sm6150-pinctrl"; - reg = <0x03000000 0xdc2000>; + reg = <0x03000000 0xdc2000>, <0x17c000f0 0x60>; + reg-names = "pinctrl", "spi_cfg"; interrupts = <0 208 0>; gpio-controller; #gpio-cells = <2>; @@ -122,7 +123,7 @@ config { pins = "gpio4", "gpio5"; drive-strength = <2>; - bias-pull-up; + bias-no-pull; }; }; }; @@ -868,37 +869,6 @@ }; }; - /* USB C analog configuration */ - wcd_usbc_analog_en1 { - wcd_usbc_analog_en1_idle: wcd_usbc_ana_en1_idle { - mux { - pins = "gpio49"; - function = "gpio"; - }; - - config { - pins = "gpio49"; - drive-strength = <2>; - bias-pull-down; - output-low; - }; - }; - - wcd_usbc_analog_en1_active: wcd_usbc_ana_en1_active { - mux { - pins = "gpio49"; - function = "gpio"; - }; - - config { - pins = "gpio49"; - drive-strength = <2>; - bias-disable; - output-high; - }; - }; - }; - wsa_swr_clk_pin { wsa_swr_clk_sleep: wsa_swr_clk_sleep { mux { @@ -1113,6 +1083,47 @@ }; }; + pcie0 { + pcie0_clkreq_default: pcie0_clkreq_default { + mux { + pins = "gpio90"; + function = "pcie_clk"; + }; + + config { + pins = "gpio90"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + pcie0_perst_default: pcie0_perst_default { + mux { + pins = "gpio101"; + function = "gpio"; + }; + + config { + pins = "gpio101"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + pcie0_wake_default: pcie0_wake_default { + mux { + pins = "gpio100"; + function = "gpio"; + }; + + config { + pins = "gpio100"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + pmx_ts_int_active { ts_int_active: ts_int_active { mux { @@ -1444,6 +1455,217 @@ }; }; }; + emac { + emac_mdc: emac_mdc { + mux { + pins = "gpio113"; + function = "rgmii_mdc"; + }; + + config { + pins = "gpio113"; + bias-pull-up; + }; + }; + emac_mdio: emac_mdio { + mux { + pins = "gpio114"; + function = "rgmii_mdio"; + }; + + config { + pins = "gpio114"; + bias-pull-up; + }; + }; + + emac_rgmii_txd0: emac_rgmii_txd0 { + mux { + pins = "gpio96"; + function = "rgmii_txd0"; + }; + + config { + pins = "gpio96"; + bias-pull-up; + drive-strength = <16>; + }; + }; + + emac_rgmii_txd1: emac_rgmii_txd1 { + mux { + pins = "gpio95"; + function = "rgmii_txd1"; + }; + + config { + pins = "gpio95"; + bias-pull-up; + drive-strength = <16>; + }; + }; + + emac_rgmii_txd2: emac_rgmii_txd2 { + mux { + pins = "gpio94"; + function = "rgmii_txd2"; + }; + + config { + pins = "gpio94"; + bias-pull-up; + drive-strength = <16>; + }; + }; + emac_rgmii_txd3: emac_rgmii_txd3 { + mux { + pins = "gpio93"; + function = "rgmii_txd3"; + }; + + config { + pins = "gpio93"; + bias-pull-up; + drive-strength = <16>; + }; + }; + emac_rgmii_txc: emac_rgmii_txc { + mux { + pins = "gpio92"; + function = "rgmii_txc"; + }; + + config { + pins = "gpio92"; + bias-pull-up; + drive-strength = <16>; + }; + }; + emac_rgmii_tx_ctl: emac_rgmii_tx_ctl { + mux { + pins = "gpio97"; + function = "rgmii_tx"; + }; + + config { + pins = "gpio97"; + bias-pull-up; + drive-strength = <16>; + }; + }; + + + emac_rgmii_rxd0: emac_rgmii_rxd0 { + mux { + pins = "gpio83"; + function = "rgmii_rxd0"; + }; + + config { + pins = "gpio83"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2MA */ + }; + }; + + emac_rgmii_rxd1: emac_rgmii_rxd1 { + mux { + pins = "gpio82"; + function = "rgmii_rxd1"; + }; + + config { + pins = "gpio82"; + bias-disable; /* NO pull */ + drive-strength = <2>; + }; + }; + + emac_rgmii_rxd2: emac_rgmii_rxd2 { + mux { + pins = "gpio81"; + function = "rgmii_rxd2"; + }; + + config { + pins = "gpio81"; + bias-disable; /* NO pull */ + drive-strength = <2>; + }; + }; + emac_rgmii_rxd3: emac_rgmii_rxd3 { + mux { + pins = "gpio103"; + function = "rgmii_rxd3"; + }; + + config { + pins = "gpio103"; + bias-disable; /* NO pull */ + drive-strength = <2>; + }; + }; + emac_rgmii_rxc: emac_rgmii_rxc { + mux { + pins = "gpio102"; + function = "rgmii_rxc"; + }; + + config { + pins = "gpio102"; + bias-disable; /* NO pull */ + drive-strength = <2>; + }; + }; + emac_rgmii_rx_ctl: emac_rgmii_rx_ctl { + mux { + pins = "gpio112"; + function = "rgmii_rx"; + }; + + config { + pins = "gpio112"; + bias-disable; /* NO pull */ + drive-strength = <2>; + }; + }; + emac_phy_intr: emac_phy_intr { + mux { + pins = "gpio121"; + function = "emac_phy"; + }; + + config { + pins = "gpio121"; + bias-disable; /* NO pull */ + drive-strength = <2>; + }; + }; + emac_phy_reset_state: emac_phy_reset_state { + mux { + pins = "gpio104"; + function = "gpio"; + }; + + config { + pins = "gpio104"; + bias-pull-up; + drive-strength = <16>; + }; + }; + emac_pin_pps_0: emac_pin_pps_0 { + mux { + pins = "gpio91"; + function = "rgmii_sync"; + }; + + config { + pins = "gpio91"; + bias-pull-up; + drive-strength = <16>; + }; + }; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi index 6efcdcface298dfd75baffa2f1d785e2af379bfa..547ef4579963b8c64d5298d1d5a65257c5f3774d 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-qrd.dtsi @@ -61,6 +61,7 @@ &pm6150l_wled { qcom,string-cfg= <3>; + qcom,leds-per-string = <7>; status = "ok"; }; @@ -109,14 +110,17 @@ <&pm6150_vadc ADC_USB_IN_I>, <&pm6150_vadc ADC_CHG_TEMP>, <&pm6150_vadc ADC_DIE_TEMP>, - <&pm6150_vadc ADC_AMUX_THM4_PU2>; + <&pm6150_vadc ADC_AMUX_THM4_PU2>, + <&pm6150_vadc ADC_SBUx>, + <&pm6150_vadc ADC_VPH_PWR>; io-channel-names = "usb_in_voltage", "usb_in_current", "chg_temp", "die_temp", - "conn_temp"; + "conn_temp", + "sbux_res", + "vph_voltage"; qcom,battery-data = <&mtp_batterydata>; - qcom,step-charging-enable; qcom,sw-jeita-enable; qcom,fcc-stepping-enable; qcom,sec-charger-config = <1>; @@ -244,3 +248,17 @@ }; }; + +/* Primary USB port related High Speed PHY */ +&qusb_phy0 { + qcom,qusb-phy-init-seq = <0xf8 0x80 + 0xb3 0x84 + 0x83 0x88 + 0x07 0x8c + 0x30 0x08 + 0x79 0x0c + 0x21 0x10 + 0x14 0x9c + 0x9f 0x1c + 0x00 0x18>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi index 33ab2dafa7344ca33bf4351e6c7350adcaec27c7..760232fb64dcdb442c07f9869eaeb26f268f22a1 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-sde-display.dtsi @@ -236,7 +236,7 @@ &dsi_hx83112a_truly_video { qcom,mdss-dsi-t-clk-post = <0x0e>; qcom,mdss-dsi-t-clk-pre = <0x31>; - qcom,mdss-dsi-min-refresh-rate = <53>; + qcom,mdss-dsi-min-refresh-rate = <48>; qcom,mdss-dsi-max-refresh-rate = <60>; qcom,mdss-dsi-pan-enable-dynamic-fps; qcom,mdss-dsi-pan-fps-update = diff --git a/arch/arm64/boot/dts/qcom/sm6150-sde.dtsi b/arch/arm64/boot/dts/qcom/sm6150-sde.dtsi index d57fa6f9f736c91b7db5a74ec6785b001458ee34..953939f7917ccb579c84a4a65198b5f35ee19692 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-sde.dtsi @@ -35,6 +35,7 @@ "lut_clk", "rot_clk"; clock-rate = <0 0 0 256000000 19200000 192000000>; clock-max-rate = <0 0 0 307000000 19200000 307000000>; + qcom,dss-cx-ipeak = <&cx_ipeak_lm 3>; sde-vdd-supply = <&mdss_core_gdsc>; diff --git a/arch/arm64/boot/dts/qcom/sm6150-thermal.dtsi b/arch/arm64/boot/dts/qcom/sm6150-thermal.dtsi index 2c3b9e081356cec96c698b687cfddac9e3bb95d1..7f75ab1f3e9c03a15fa6c63778a381c48901d180 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-thermal.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-thermal.dtsi @@ -86,6 +86,12 @@ }; }; }; + + cxip_cdev: cxip-cdev@1fed000 { + compatible = "qcom,cxip-lm-cooling-device"; + reg = <0x1fed000 0x24>; + #cooling-cells = <2>; + }; }; &thermal_zones { @@ -1362,6 +1368,26 @@ }; }; + q6-hvx-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 10>; + thermal-governor = "step_wise"; + trips { + q6_hvx_config: q6-hvx-config { + temperature = <95000>; + hysteresis = <20000>; + type = "passive"; + }; + }; + cooling-maps { + cxip-cdev { + trip = <&q6_hvx_config>; + cooling-device = <&cxip_cdev 1 1>; + }; + }; + }; + xo-therm { polling-delay-passive = <0>; polling-delay = <0>; diff --git a/arch/arm64/boot/dts/qcom/sm6150-usb.dtsi b/arch/arm64/boot/dts/qcom/sm6150-usb.dtsi index 035adb3fef537d0dc7d05f36615ecabf45c7ba82..7b48fa99760ceac8ce250a02bb365964310f1633 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-usb.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150-usb.dtsi @@ -55,6 +55,7 @@ 0x144 /* GSI_RING_BASE_ADDR_H */ 0x1a4>; /* GSI_IF_STS */ qcom,dwc-usb3-msm-tx-fifo-size = <21288>; + qcom,pm-qos-latency = <61>; qcom,msm-bus,name = "usb0"; qcom,msm-bus,num-cases = <4>; @@ -160,7 +161,7 @@ qcom,major-rev = <1>; clocks = <&clock_rpmh RPMH_CXO_CLK>, - <&clock_gcc GCC_USB2_PRIM_CLKREF_CLK>, + <&clock_gcc GCC_RX1_USB2_CLKREF_CLK>, <&clock_gcc GCC_AHB2PHY_WEST_CLK>; clock-names = "ref_clk_src", "ref_clk", "cfg_ahb_clk"; @@ -171,8 +172,10 @@ /* Primary USB port related QMP USB PHY */ usb_qmp_phy: ssphy@88e6000 { compatible = "qcom,usb-ssphy-qmp-usb3-or-dp"; - reg = <0x88e6000 0x1000>; - reg-names = "qmp_phy_base"; + reg = <0x88e6000 0x1000>, + <0x01fcb244 0x4>; + reg-names = "qmp_phy_base", + "vls_clamp_reg"; vdd-supply = <&pm6150_l4>; core-supply = <&pm6150_l11>; @@ -296,7 +299,7 @@ clocks = <&clock_gcc GCC_USB3_PRIM_PHY_AUX_CLK>, <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, - <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_RX3_USB2_CLKREF_CLK>, <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>, <&clock_gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>, <&clock_gcc GCC_AHB2PHY_WEST_CLK>; @@ -410,7 +413,7 @@ qcom,hold-reset; clocks = <&clock_rpmh RPMH_CXO_CLK>, - <&clock_gcc GCC_USB2_SEC_CLKREF_CLK>, + <&clock_gcc GCC_RX3_USB2_CLKREF_CLK>, <&clock_gcc GCC_AHB2PHY_WEST_CLK>; clock-names = "ref_clk_src", "ref_clk", "cfg_ahb_clk"; diff --git a/arch/arm64/boot/dts/qcom/sm6150-usbc-idp-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150-usbc-idp-overlay.dts index 015e7e10cddea49aeadf5a23d7e13ee4c2a35c98..c56081f944305bd26cda5e77f2d20f756ef0287e 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-usbc-idp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-usbc-idp-overlay.dts @@ -17,6 +17,7 @@ #include #include "sm6150-idp.dtsi" +#include "sm6150-usbc-idp.dtsi" / { model = "USBC Audio IDP"; diff --git a/arch/arm64/boot/dts/qcom/sm6150-usbc-idp.dts b/arch/arm64/boot/dts/qcom/sm6150-usbc-idp.dts index c71c55e349d6251f707d7ed91dc5804dab04ee35..dc1c415d21f2474a902f3dd7e8baf3d6b04dc7ab 100644 --- a/arch/arm64/boot/dts/qcom/sm6150-usbc-idp.dts +++ b/arch/arm64/boot/dts/qcom/sm6150-usbc-idp.dts @@ -14,6 +14,7 @@ #include "sm6150.dtsi" #include "sm6150-idp.dtsi" +#include "sm6150-usbc-idp.dtsi" / { model = "Qualcomm Technologies, Inc. SM6150 PM6150 USBC Audio IDP"; diff --git a/arch/arm64/boot/dts/qcom/sm6150-usbc-idp.dtsi b/arch/arm64/boot/dts/qcom/sm6150-usbc-idp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..0437415f502fe854d8394a85a516e88bf19f8359 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm6150-usbc-idp.dtsi @@ -0,0 +1,17 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "sm6150-audio-overlay.dtsi" + +&sm6150_snd { + qcom,msm-mbhc-usbc-audio-supported = <1>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-usbc-minidp-idp-overlay.dts b/arch/arm64/boot/dts/qcom/sm6150-usbc-minidp-idp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..13c16e602fcf5f0989ea43556b1ccde2b035948f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm6150-usbc-minidp-idp-overlay.dts @@ -0,0 +1,26 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include +#include + +#include "sm6150-idp.dtsi" + +/ { + model = "USBC mini DP Primary Panel IDP"; + compatible = "qcom,sm6150-idp", "qcom,sm6150", "qcom,idp"; + qcom,msm-id = <355 0x0>; + qcom,board-id = <34 4>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150-usbc-minidp-idp.dts b/arch/arm64/boot/dts/qcom/sm6150-usbc-minidp-idp.dts new file mode 100644 index 0000000000000000000000000000000000000000..5381c6619ffbc99a724e31c9e4f2b5bd26baf797 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm6150-usbc-minidp-idp.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sm6150.dtsi" +#include "sm6150-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SM6150 PM6150 USBC mini DP Primary Panel IDP"; + compatible = "qcom,sm6150-idp", "qcom,sm6150", "qcom,idp"; + qcom,board-id = <34 4>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index e8ca00a4f2f7e280287c610987737fcb3c463dac..fdc2f2356de81b750e75bdda9d273cf8e6c59959 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -511,7 +511,7 @@ xbl_aop_mem: xbl_aop_mem@85e00000 { compatible = "removed-dma-pool"; no-map; - reg = <0x0 0x85e00000 0x0 0x1ff000>; + reg = <0x0 0x85e00000 0x0 0x140000>; }; sec_apps_mem: sec_apps_region@85fff000 { @@ -559,31 +559,31 @@ pil_cdsp_mem: cdsp_regions@93400000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x93400000 0 0x800000>; + reg = <0 0x93400000 0 0x1e00000>; }; - pil_adsp_mem: pil_adsp_region@93c00000 { + pil_adsp_mem: pil_adsp_region@95200000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x93c00000 0 0x1e00000>; + reg = <0 0x95200000 0 0x1e00000>; }; - pil_ipa_fw_mem: ips_fw_region@0x95a00000 { + pil_ipa_fw_mem: ips_fw_region@0x97000000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x95a00000 0 0x10000>; + reg = <0 0x97000000 0 0x10000>; }; - pil_ipa_gsi_mem: ipa_gsi_region@0x95a10000 { + pil_ipa_gsi_mem: ipa_gsi_region@0x97010000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x95a10000 0 0x5000>; + reg = <0 0x97010000 0 0x5000>; }; - pil_gpu_mem: gpu_region@0x95a15000 { + pil_gpu_mem: gpu_region@0x97015000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x95a15000 0 0x2000>; + reg = <0 0x97015000 0 0x2000>; }; qseecom_mem: qseecom_region@0x9e400000 { @@ -592,6 +592,12 @@ reg = <0 0x9e400000 0 0x1400000>; }; + cdsp_sec_mem: cdsp_sec_regions@0x9f800000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x9f800000 0x0 0xc00000>; + }; + adsp_mem: adsp_region { compatible = "shared-dma-pool"; alloc-ranges = <0 0x00000000 0 0xffffffff>; @@ -1702,6 +1708,10 @@ <&apps_smmu 0x0116 0x0011>; }; + qcom_msmhdcp: qcom,msm_hdcp { + compatible = "qcom,msm-hdcp"; + }; + qcom_crypto: qcrypto@1de0000 { compatible = "qcom,qcrypto"; reg = <0x1de0000 0x20000>, @@ -1778,8 +1788,10 @@ compatible = "qcom,msm-eud"; interrupt-names = "eud_irq"; interrupts = ; - reg = <0x88e0000 0x2000>; - reg-names = "eud_base"; + reg = <0x88e0000 0x2000>, + <0x88e4000 0x1000>; + reg-names = "eud_base", "eud_mode_mgr2"; + qcom,secure-eud-en; status = "ok"; }; @@ -2057,6 +2069,23 @@ qcom,intents = <0x64 64>; }; + qcom,msm_cdsprm_rpmsg { + compatible = "qcom,msm-cdsprm-rpmsg"; + qcom,glink-channels = "cdsprmglink-apps-dsp"; + qcom,intents = <0x20 12>; + + qcom,cdsp-cdsp-l3-gov { + compatible = "qcom,cdsp-l3"; + qcom,target-dev = <&cdsp_cdsp_l3_lat>; + }; + + qcom,msm_cdsp_rm { + compatible = "qcom,msm-cdsp-rm"; + qcom,qos-latency-us = <44>; + qcom,qos-maxhold-ms = <20>; + }; + }; + qcom,cdsp_glink_ssr { qcom,glink-channels = "glink_ssr"; qcom,notify-edges = <&glink_modem>, @@ -2167,6 +2196,9 @@ qcom,smp2p_sleepstate { compatible = "qcom,smp2p-sleepstate"; qcom,smem-states = <&sleepstate_smp2p_out 0>; + interrupt-parent = <&sleepstate_smp2p_in>; + interrupts = <0 0>; + interrupt-names = "smp2p-sleepstate-in"; }; qcom,smp2p-modem { @@ -2230,6 +2262,12 @@ qcom,entry-name = "sleepstate"; #qcom,smem-state-cells = <1>; }; + + sleepstate_smp2p_in: qcom,sleepstate-in { + qcom,entry-name = "sleepstate_see"; + interrupt-controller; + #interrupt-cells = <2>; + }; }; qcom,smp2p-cdsp { @@ -2681,6 +2719,7 @@ qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; qcom,target-dev = <&cpu0_cpu_l3_lat>; qcom,cachemiss-ev = <0x17>; + qcom,stall-cycle-ev = <0xE7>; qcom,core-dev-table = < 576000 300000000 >, < 1017600 556800000 >, @@ -2701,6 +2740,7 @@ qcom,cpulist = <&CPU6 &CPU7>; qcom,target-dev = <&cpu6_cpu_l3_lat>; qcom,cachemiss-ev = <0x17>; + qcom,stall-cycle-ev = <0x15E>; qcom,core-dev-table = < 1017600 556800000 >, < 1209600 806400000 >, @@ -2723,6 +2763,7 @@ qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; qcom,target-dev = <&cpu0_cpu_llcc_lat>; qcom,cachemiss-ev = <0x2A>; + qcom,stall-cycle-ev = <0xE7>; qcom,core-dev-table = < 748000 MHZ_TO_MBPS(150, 16) >, < 1209600 MHZ_TO_MBPS(300, 16) >, @@ -2744,6 +2785,7 @@ qcom,cpulist = <&CPU6 &CPU7>; qcom,target-dev = <&cpu6_cpu_llcc_lat>; qcom,cachemiss-ev = <0x2A>; + qcom,stall-cycle-ev = <0x15E>; qcom,core-dev-table = < 768000 MHZ_TO_MBPS(300, 16) >, < 1017600 MHZ_TO_MBPS(466, 16) >, @@ -2766,6 +2808,7 @@ qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; qcom,target-dev = <&cpu0_llcc_ddr_lat>; qcom,cachemiss-ev = <0x1000>; + qcom,stall-cycle-ev = <0xE7>; qcom,core-dev-table = < 748000 MHZ_TO_MBPS( 300, 4) >, < 1017600 MHZ_TO_MBPS( 451, 4) >, @@ -2788,6 +2831,7 @@ qcom,cpulist = <&CPU6 &CPU7>; qcom,target-dev = <&cpu6_llcc_ddr_lat>; qcom,cachemiss-ev = <0x1000>; + qcom,stall-cycle-ev = <0x15E>; qcom,core-dev-table = < 768000 MHZ_TO_MBPS( 451, 4) >, < 1017600 MHZ_TO_MBPS( 547, 4) >, @@ -2854,6 +2898,10 @@ compatible = "qcom,cx-ipeak-sm6150"; reg = <0x1fed000 0x28>; }; + + demux { + compatible = "qcom,demux"; + }; }; #include "pm6150.dtsi" @@ -3049,6 +3097,7 @@ }; &bps_gdsc { + qcom,support-hw-trigger; status = "ok"; }; @@ -3061,6 +3110,7 @@ }; &ipe_0_gdsc { + qcom,support-hw-trigger; status = "ok"; }; @@ -3094,6 +3144,16 @@ status = "ok"; }; +&qupv3_se3_i2c { + status = "ok"; + fsa4480: fsa4480@43 { + compatible = "qcom,fsa4480-i2c"; + reg = <0x43>; + pinctrl-names = "default"; + pinctrl-0 = <&fsa_usbc_ana_en>; + }; +}; + #include "sm6150-camera.dtsi" #include "sm6150-ion.dtsi" #include "msm-arm-smmu-sm6150.dtsi" @@ -3103,3 +3163,8 @@ #include "sm6150-audio.dtsi" #include "sm6150-sde-pll.dtsi" #include "sm6150-sde.dtsi" + +&msm_vidc { + qcom,cx-ipeak-data = <&cx_ipeak_lm 4>; + qcom,clock-freq-threshold = <380000000>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-adp-star.dtsi b/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-adp-star.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9bac609b3b04157a7d589a17cb6b925eb52f4029 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150-camera-sensor-adp-star.dtsi @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&cam_cci0 { + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; + + qcom,cam-sensor@0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + reg = <0x0>; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&pm8150_1_s4>; + cam_bob-supply = <&pm8150_1_s4>; + cam_vana-supply = <&pm8150_1_s4>; + cam_vdig-supply = <&pm8150_1_s4>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + gpios = <&tlmm 13 0>, + <&tlmm 21 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x1>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_bob-supply = <&pm8150_1_s4>; + cam_vdig-supply = <&pm8150_1_s4>; + cam_vio-supply = <&pm8150_1_s4>; + cam_vana-supply = <&pm8150_1_s4>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + gpios = <&tlmm 14 0>, + <&tlmm 22 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + reg = <0x02>; + csiphy-sd-index = <2>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + cam_vio-supply = <&pm8150_1_s4>; + cam_bob-supply = <&pm8150_1_s4>; + cam_vana-supply = <&pm8150_1_s4>; + cam_vdig-supply = <&pm8150_1_s4>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + gpios = <&tlmm 15 0>, + <&tlmm 23 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@3 { + cell-index = <3>; + compatible = "qcom,cam-sensor"; + reg = <0x03>; + csiphy-sd-index = <3>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + cam_vio-supply = <&pm8150_1_s4>; + cam_bob-supply = <&pm8150_1_s4>; + cam_vana-supply = <&pm8150_1_s4>; + cam_vdig-supply = <&pm8150_1_s4>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + gpios = <&tlmm 16 0>, + <&tlmm 25 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi b/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi index 2f7244fe585dc0f8dcf041ce971368c862e27f81..49372b527452e2adefa319c6a50371b26eaf4791 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-mtp.dtsi @@ -305,6 +305,7 @@ qcom,battery-data = <&mtp_batterydata>; qcom,hold-soc-while-full; qcom,linearize-soc; + qcom,five-pin-battery; /* ESR fast calibration */ qcom,fg-esr-timer-chg-fast = <0 7>; qcom,fg-esr-timer-dischg-fast = <0 7>; @@ -615,12 +616,12 @@ &pm8150b_charger { qcom,sec-charger-config = <3>; qcom,auto-recharge-soc = <98>; - io-channels = <&pm8150b_vadc ADC_USB_IN_V_16>, + io-channels = <&pm8150b_vadc ADC_MID_CHG_DIV6>, <&pm8150b_vadc ADC_USB_IN_I>, <&pm8150b_vadc ADC_SBUx>, <&pm8150b_vadc ADC_VPH_PWR>, <&pm8150b_vadc ADC_CHG_TEMP>; - io-channel-names = "usb_in_voltage", + io-channel-names = "mid_voltage", "usb_in_current", "sbux_res", "vph_voltage", diff --git a/arch/arm64/boot/dts/qcom/sm8150-npu.dtsi b/arch/arm64/boot/dts/qcom/sm8150-npu.dtsi index 44ad4847e03b513d8e01d20ed9031469f1a47e67..83c8f51629542c6479e66eaeb17dce863884b042 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-npu.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-npu.dtsi @@ -67,8 +67,8 @@ vdd_cx-supply = <&VDD_CX_LEVEL>; qcom,proxy-reg-names ="vdd", "vdd_cx"; qcom,vdd_cx-uV-uA = ; - mboxes = <&qmp_npu0 0>, <&qmp_npu1 0>; - mbox-names = "npu_low", "npu_high"; + mboxes = <&qmp_aop 0>; + mbox-names = "aop"; #cooling-cells = <2>; qcom,npubw-dev = <&npu_npu_ddr_bw>; qcom,npu-pwrlevels { diff --git a/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi index eb833f080f75de4d7439da257b6813451d7692af..006b10539512932e76555fa14b1e3753d4a73d33 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi @@ -13,7 +13,8 @@ &soc { tlmm: pinctrl@03000000 { compatible = "qcom,sm8150-pinctrl"; - reg = <0x03000000 0xdc2000>; + reg = <0x03000000 0xdc2000>, <0x17c000f0 0x60>; + reg-names = "pinctrl", "spi_cfg"; interrupts = <0 208 0>; gpio-controller; #gpio-cells = <2>; diff --git a/arch/arm64/boot/dts/qcom/sm8150-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sm8150-pmic-overlay.dtsi index 40b8621dcc200b15b5c6b036849a984315892337..7f6e1623ff11aca2aea77b86af65d20417513634 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-pmic-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-pmic-overlay.dtsi @@ -104,3 +104,7 @@ &usb0 { extcon = <&pm8150b_pdphy>, <&eud>; }; + +&usb_qmp_dp_phy { + extcon = <&pm8150b_pdphy>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi index cc4217d391633f009c94206b950913de3ea33519..76dd5f9d644fb9f1c68cff491584b65cf1349bc6 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi @@ -49,6 +49,7 @@ qcom,battery-data = <&qrd_batterydata>; qcom,hold-soc-while-full; qcom,linearize-soc; + qcom,five-pin-battery; /* ESR fast calibration */ qcom,fg-esr-timer-chg-fast = <0 7>; qcom,fg-esr-timer-dischg-fast = <0 7>; @@ -563,12 +564,12 @@ &pm8150b_charger { qcom,sec-charger-config = <1>; qcom,auto-recharge-soc = <98>; - io-channels = <&pm8150b_vadc ADC_USB_IN_V_16>, + io-channels = <&pm8150b_vadc ADC_MID_CHG_DIV6>, <&pm8150b_vadc ADC_USB_IN_I>, <&pm8150b_vadc ADC_SBUx>, <&pm8150b_vadc ADC_VPH_PWR>, <&pm8150b_vadc ADC_CHG_TEMP>; - io-channel-names = "usb_in_voltage", + io-channel-names = "mid_voltage", "usb_in_current", "sbux_res", "vph_voltage", diff --git a/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi index 0cf1db83d2f4c3606202e4c4919cba9ce920b1d3..637be62f134a6ae8097f15587365902edabaf2c0 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi @@ -698,10 +698,11 @@ qcom,mdss-dsi-display-timings { timing@0{ - qcom,mdss-dsi-panel-phy-timings = [00 1A 06 06 22 20 07 - 07 04 02 04 00]; + qcom,mdss-dsi-panel-phy-timings = [00 1E 08 08 24 22 08 + 08 05 02 04 00]; qcom,display-topology = <1 0 1>; qcom,default-topology-index = <0>; + qcom,mdss-dsi-panel-clockrate = <900000000>; }; }; }; @@ -858,6 +859,13 @@ }; &dsi_sw43404_amoled_video { + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; qcom,mdss-dsi-display-timings { timing@0 { qcom,mdss-dsi-panel-phy-timings = [00 1a 07 06 22 21 07 @@ -870,8 +878,8 @@ }; &dsi_sharp_1080_cmd { - qcom,mdss-dsi-t-clk-post = <0x16>; - qcom,mdss-dsi-t-clk-pre = <0x16>; + qcom,mdss-dsi-t-clk-post = <0x18>; + qcom,mdss-dsi-t-clk-pre = <0x19>; qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 1A 06 06 22 20 07 diff --git a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi index d116952920343685a944bcc0a50778bf3389f7b0..2ee3695d0d04e54b1b13e1f27195dc675c324f75 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi @@ -149,6 +149,7 @@ qcom,sde-highest-bank-bit = <0x2>; qcom,sde-ubwc-version = <0x300>; qcom,sde-ubwc-bw-calc-version = <0x1>; + qcom,sde-smart-panel-align-mode = <0xc>; qcom,sde-panic-per-pipe; qcom,sde-has-cdp; qcom,sde-has-src-split; diff --git a/arch/arm64/boot/dts/qcom/sm8150-sdx50m-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sm8150-sdx50m-cdp-overlay.dts index defed2390aae3b4b40afd07317a60db2538c33d2..5a76be032547e2ab095b816682065d8c5c81425c 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sdx50m-cdp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm8150-sdx50m-cdp-overlay.dts @@ -20,7 +20,7 @@ #include "sm8150-cdp.dtsi" -#include "sdx50m-external-soc.dtsi" +#include "sdx5xm-external-soc.dtsi" #include "sm8150-sdx50m.dtsi" #include "sm8150-cdp-audio-overlay.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sm8150-sdx50m-mtp-2.5k-panel-overlay.dts b/arch/arm64/boot/dts/qcom/sm8150-sdx50m-mtp-2.5k-panel-overlay.dts index 9f6e83451448a31903b3b3b187f9e73c52eced2a..8020e287fc5336b0fa39f0b7a61f4deac4b15230 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sdx50m-mtp-2.5k-panel-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm8150-sdx50m-mtp-2.5k-panel-overlay.dts @@ -20,7 +20,7 @@ #include "sm8150-mtp.dtsi" -#include "sdx50m-external-soc.dtsi" +#include "sdx5xm-external-soc.dtsi" #include "sm8150-sdx50m.dtsi" #include "sm8150-mtp-audio-overlay.dtsi" @@ -59,3 +59,8 @@ &dsi_dual_nt35597_truly_cmd_display { qcom,dsi-display-active; }; + +&pm8150l_wled { + qcom,string-cfg = <6>; + qcom,leds-per-string = <8>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-sdx50m-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sm8150-sdx50m-mtp-overlay.dts index 3270a735a803f76b454931da15d27ccde9cd20fc..fb74f162754f93c1e76e1f3e6e4a7e28932f2b07 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sdx50m-mtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm8150-sdx50m-mtp-overlay.dts @@ -20,7 +20,7 @@ #include "sm8150-mtp.dtsi" -#include "sdx50m-external-soc.dtsi" +#include "sdx5xm-external-soc.dtsi" #include "sm8150-sdx50m.dtsi" #include "sm8150-mtp-audio-overlay.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sm8150-sdx50m-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sm8150-sdx50m-qrd-overlay.dts index 8d384978ba3a081832593f43e3fe4ddc88608b2d..24591dc16cea639d7660c1d04a0c3c9f3b4c4df6 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sdx50m-qrd-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sm8150-sdx50m-qrd-overlay.dts @@ -20,7 +20,7 @@ #include "sm8150-qrd.dtsi" -#include "sdx50m-external-soc.dtsi" +#include "sdx5xm-external-soc.dtsi" #include "sm8150-sdx50m.dtsi" #include "sm8150-sdx50m-audio-overlay.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi index 10f831205a19e7adc05773943c91a6b5a57eeb8d..f94c3a39b8c7a3d4636125b652371ede35882def 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sdx50m.dtsi @@ -11,31 +11,8 @@ */ &mdm3 { - pinctrl-names = "default", "mdm_active", "mdm_suspend"; - pinctrl-0 = <&ap2mdm_pon_reset_default>; - pinctrl-1 = <&ap2mdm_active &mdm2ap_active>; - pinctrl-2 = <&ap2mdm_sleep &mdm2ap_sleep>; - interrupt-map = <0 &tlmm 53 0x3 - 1 &tlmm 135 0x3>; - qcom,mdm2ap-errfatal-gpio = <&tlmm 53 0x00>; - qcom,ap2mdm-errfatal-gpio = <&tlmm 141 0x00>; - qcom,mdm2ap-status-gpio = <&tlmm 142 0x00>; - qcom,ap2mdm-status-gpio = <&tlmm 135 0x00>; - qcom,ap2mdm-soft-reset-gpio = <&pm8150l_gpios 9 0>; + compatible = "qcom,ext-sdx50m"; qcom,mdm-link-info = "0305_01.01.00"; - qcom,esoc-skip-restart-for-mdm-crash; - status = "ok"; -}; - -&pm8150l_gpios { - ap2mdm_pon_reset { - ap2mdm_pon_reset_default: ap2mdm_pon_reset_default { - /* MDM PON conrol*/ - pins = "gpio9"; - function = "normal"; - power-source = <1>; /* 1.8V */ - }; - }; }; &wil6210 { diff --git a/arch/arm64/boot/dts/qcom/sm8150-sdxprairie-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sm8150-sdxprairie-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..75b3fca5e9bd6202d3c906c116174becdba6a826 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150-sdxprairie-cdp-overlay.dts @@ -0,0 +1,31 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +#include "sm8150-cdp.dtsi" + +#include "sdx5xm-external-soc.dtsi" +#include "sm8150-sdxprairie.dtsi" +#include "sm8150-cdp-audio-overlay.dtsi" + +/ { + model = "SDXPRAIRIE CDP"; + compatible = "qcom,sm8150-cdp", "qcom,sm8150", "qcom,cdp"; + qcom,board-id = <1 3>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-sdxprairie-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sm8150-sdxprairie-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..c70c4a92fe906569943deb746214db581744c475 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150-sdxprairie-mtp-overlay.dts @@ -0,0 +1,31 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +#include "sm8150-mtp.dtsi" + +#include "sdx5xm-external-soc.dtsi" +#include "sm8150-sdxprairie.dtsi" +#include "sm8150-mtp-audio-overlay.dtsi" + +/ { + model = "SDXPRAIRIE MTP"; + compatible = "qcom,sm8150-mtp", "qcom,sm8150", "qcom,mtp"; + qcom,board-id = <8 3>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8150-sdxprairie.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sdxprairie.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..f48bdb56af96feb95bcbff4d67d6c619dbb23dfa --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8150-sdxprairie.dtsi @@ -0,0 +1,17 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&mdm3 { + compatible = "qcom,ext-sdxprairie"; + qcom,mdm-link-info = "0306_01.01.00"; +}; + diff --git a/arch/arm64/boot/dts/qcom/sm8150-thermal.dtsi b/arch/arm64/boot/dts/qcom/sm8150-thermal.dtsi index 456ff38abd06f3b2b73873ae4923e5c12dde8c92..dddb1a95c555bbebbc900557baa8388d1e6cb0bf 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-thermal.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-thermal.dtsi @@ -493,1378 +493,14 @@ }; }; - aoss0-lowf { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-governor = "low_limits_floor"; - thermal-sensors = <&tsens0 0>; - tracks-low; - trips { - aoss0_trip: aoss0-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_cdev { - trip = <&aoss0_trip>; - cooling-device = <&CPU0 1 1>; - }; - cpu1_cdev { - trip = <&aoss0_trip>; - cooling-device = <&CPU4 5 5>; - }; - cx_vdd_cdev { - trip = <&aoss0_trip>; - cooling-device = <&cx_cdev 0 0>; - }; - mx_vdd_cdev { - trip = <&aoss0_trip>; - cooling-device = <&mx_cdev 0 0>; - }; - ebi_vdd_cdev { - trip = <&aoss0_trip>; - cooling-device = <&ebi_cdev 0 0>; - }; - mmcx_vdd_cdev { - trip = <&aoss0_trip>; - cooling-device = <&mm_cx_cdev 0 0>; - }; - modem_vdd_cdev { - trip = <&aoss0_trip>; - cooling-device = <&modem_vdd 0 0>; - }; - adsp_vdd_cdev { - trip = <&aoss0_trip>; - cooling-device = <&adsp_vdd 0 0>; - }; - cdsp_vdd_cdev { - trip = <&aoss0_trip>; - cooling-device = <&cdsp_vdd 0 0>; - }; - slpi_vdd_cdev { - trip = <&aoss0_trip>; - cooling-device = <&slpi_vdd 0 0>; - }; - gpu_vdd_cdev { - trip = <&aoss0_trip>; - cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) - (THERMAL_MAX_LIMIT-2)>; - }; - }; - }; - - cpu-0-0-lowf { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-governor = "low_limits_floor"; - thermal-sensors = <&tsens0 1>; - tracks-low; - trips { - cpu00_trip: cpu00-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_cdev { - trip = <&cpu00_trip>; - cooling-device = <&CPU0 1 1>; - }; - cpu1_cdev { - trip = <&cpu00_trip>; - cooling-device = <&CPU4 5 5>; - }; - cx_vdd_cdev { - trip = <&cpu00_trip>; - cooling-device = <&cx_cdev 0 0>; - }; - mx_vdd_cdev { - trip = <&cpu00_trip>; - cooling-device = <&mx_cdev 0 0>; - }; - ebi_vdd_cdev { - trip = <&cpu00_trip>; - cooling-device = <&ebi_cdev 0 0>; - }; - mmcx_vdd_cdev { - trip = <&cpu00_trip>; - cooling-device = <&mm_cx_cdev 0 0>; - }; - modem_vdd_cdev { - trip = <&cpu00_trip>; - cooling-device = <&modem_vdd 0 0>; - }; - adsp_vdd_cdev { - trip = <&cpu00_trip>; - cooling-device = <&adsp_vdd 0 0>; - }; - cdsp_vdd_cdev { - trip = <&cpu00_trip>; - cooling-device = <&cdsp_vdd 0 0>; - }; - slpi_vdd_cdev { - trip = <&cpu00_trip>; - cooling-device = <&slpi_vdd 0 0>; - }; - gpu_vdd_cdev { - trip = <&cpu00_trip>; - cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) - (THERMAL_MAX_LIMIT-2)>; - }; - }; - }; - - cpu-0-1-lowf { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-governor = "low_limits_floor"; - thermal-sensors = <&tsens0 2>; - tracks-low; - trips { - cpu01_trip: cpu01-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_cdev { - trip = <&cpu01_trip>; - cooling-device = <&CPU0 1 1>; - }; - cpu1_cdev { - trip = <&cpu01_trip>; - cooling-device = <&CPU4 5 5>; - }; - cx_vdd_cdev { - trip = <&cpu01_trip>; - cooling-device = <&cx_cdev 0 0>; - }; - mx_vdd_cdev { - trip = <&cpu01_trip>; - cooling-device = <&mx_cdev 0 0>; - }; - ebi_vdd_cdev { - trip = <&cpu01_trip>; - cooling-device = <&ebi_cdev 0 0>; - }; - mmcx_vdd_cdev { - trip = <&cpu01_trip>; - cooling-device = <&mm_cx_cdev 0 0>; - }; - modem_vdd_cdev { - trip = <&cpu01_trip>; - cooling-device = <&modem_vdd 0 0>; - }; - adsp_vdd_cdev { - trip = <&cpu01_trip>; - cooling-device = <&adsp_vdd 0 0>; - }; - cdsp_vdd_cdev { - trip = <&cpu01_trip>; - cooling-device = <&cdsp_vdd 0 0>; - }; - slpi_vdd_cdev { - trip = <&cpu01_trip>; - cooling-device = <&slpi_vdd 0 0>; - }; - gpu_vdd_cdev { - trip = <&cpu01_trip>; - cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) - (THERMAL_MAX_LIMIT-2)>; - }; - }; - }; - - cpu-0-2-lowf { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-governor = "low_limits_floor"; - thermal-sensors = <&tsens0 3>; - tracks-low; - trips { - cpu02_trip: cpu02-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_cdev { - trip = <&cpu02_trip>; - cooling-device = <&CPU0 1 1>; - }; - cpu1_cdev { - trip = <&cpu02_trip>; - cooling-device = <&CPU4 5 5>; - }; - cx_vdd_cdev { - trip = <&cpu02_trip>; - cooling-device = <&cx_cdev 0 0>; - }; - mx_vdd_cdev { - trip = <&cpu02_trip>; - cooling-device = <&mx_cdev 0 0>; - }; - ebi_vdd_cdev { - trip = <&cpu02_trip>; - cooling-device = <&ebi_cdev 0 0>; - }; - mmcx_vdd_cdev { - trip = <&cpu02_trip>; - cooling-device = <&mm_cx_cdev 0 0>; - }; - modem_vdd_cdev { - trip = <&cpu02_trip>; - cooling-device = <&modem_vdd 0 0>; - }; - adsp_vdd_cdev { - trip = <&cpu02_trip>; - cooling-device = <&adsp_vdd 0 0>; - }; - cdsp_vdd_cdev { - trip = <&cpu02_trip>; - cooling-device = <&cdsp_vdd 0 0>; - }; - slpi_vdd_cdev { - trip = <&cpu02_trip>; - cooling-device = <&slpi_vdd 0 0>; - }; - gpu_vdd_cdev { - trip = <&cpu02_trip>; - cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) - (THERMAL_MAX_LIMIT-2)>; - }; - }; - }; - - cpu-0-3-lowf { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-sensors = <&tsens0 4>; - thermal-governor = "low_limits_floor"; - tracks-low; - trips { - cpu03_trip: cpu03-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_cdev { - trip = <&cpu03_trip>; - cooling-device = <&CPU0 1 1>; - }; - cpu1_cdev { - trip = <&cpu03_trip>; - cooling-device = <&CPU4 5 5>; - }; - cx_vdd_cdev { - trip = <&cpu03_trip>; - cooling-device = <&cx_cdev 0 0>; - }; - mx_vdd_cdev { - trip = <&cpu03_trip>; - cooling-device = <&mx_cdev 0 0>; - }; - ebi_vdd_cdev { - trip = <&cpu03_trip>; - cooling-device = <&ebi_cdev 0 0>; - }; - mmcx_vdd_cdev { - trip = <&cpu03_trip>; - cooling-device = <&mm_cx_cdev 0 0>; - }; - modem_vdd_cdev { - trip = <&cpu03_trip>; - cooling-device = <&modem_vdd 0 0>; - }; - adsp_vdd_cdev { - trip = <&cpu03_trip>; - cooling-device = <&adsp_vdd 0 0>; - }; - cdsp_vdd_cdev { - trip = <&cpu03_trip>; - cooling-device = <&cdsp_vdd 0 0>; - }; - slpi_vdd_cdev { - trip = <&cpu03_trip>; - cooling-device = <&slpi_vdd 0 0>; - }; - gpu_vdd_cdev { - trip = <&cpu03_trip>; - cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) - (THERMAL_MAX_LIMIT-2)>; - }; - }; - }; - - cpuss-0-lowf { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-sensors = <&tsens0 5>; - thermal-governor = "low_limits_floor"; - tracks-low; - trips { - cpuss0_trip: cpuss0-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_cdev { - trip = <&cpuss0_trip>; - cooling-device = <&CPU0 1 1>; - }; - cpu1_cdev { - trip = <&cpuss0_trip>; - cooling-device = <&CPU4 5 5>; - }; - cx_vdd_cdev { - trip = <&cpuss0_trip>; - cooling-device = <&cx_cdev 0 0>; - }; - mx_vdd_cdev { - trip = <&cpuss0_trip>; - cooling-device = <&mx_cdev 0 0>; - }; - ebi_vdd_cdev { - trip = <&cpuss0_trip>; - cooling-device = <&ebi_cdev 0 0>; - }; - mmcx_vdd_cdev { - trip = <&cpuss0_trip>; - cooling-device = <&mm_cx_cdev 0 0>; - }; - modem_vdd_cdev { - trip = <&cpuss0_trip>; - cooling-device = <&modem_vdd 0 0>; - }; - adsp_vdd_cdev { - trip = <&cpuss0_trip>; - cooling-device = <&adsp_vdd 0 0>; - }; - cdsp_vdd_cdev { - trip = <&cpuss0_trip>; - cooling-device = <&cdsp_vdd 0 0>; - }; - slpi_vdd_cdev { - trip = <&cpuss0_trip>; - cooling-device = <&slpi_vdd 0 0>; - }; - gpu_vdd_cdev { - trip = <&cpuss0_trip>; - cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) - (THERMAL_MAX_LIMIT-2)>; - }; - }; - }; - - cpuss-1-lowf { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-sensors = <&tsens0 6>; - thermal-governor = "low_limits_floor"; - tracks-low; - trips { - cpuss1_trip: cpuss1-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_cdev { - trip = <&cpuss1_trip>; - cooling-device = <&CPU0 1 1>; - }; - cpu1_cdev { - trip = <&cpuss1_trip>; - cooling-device = <&CPU4 5 5>; - }; - cx_vdd_cdev { - trip = <&cpuss1_trip>; - cooling-device = <&cx_cdev 0 0>; - }; - mx_vdd_cdev { - trip = <&cpuss1_trip>; - cooling-device = <&mx_cdev 0 0>; - }; - ebi_vdd_cdev { - trip = <&cpuss1_trip>; - cooling-device = <&ebi_cdev 0 0>; - }; - mmcx_vdd_cdev { - trip = <&cpuss1_trip>; - cooling-device = <&mm_cx_cdev 0 0>; - }; - modem_vdd_cdev { - trip = <&cpuss1_trip>; - cooling-device = <&modem_vdd 0 0>; - }; - adsp_vdd_cdev { - trip = <&cpuss1_trip>; - cooling-device = <&adsp_vdd 0 0>; - }; - cdsp_vdd_cdev { - trip = <&cpuss1_trip>; - cooling-device = <&cdsp_vdd 0 0>; - }; - slpi_vdd_cdev { - trip = <&cpuss1_trip>; - cooling-device = <&slpi_vdd 0 0>; - }; - gpu_vdd_cdev { - trip = <&cpuss1_trip>; - cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) - (THERMAL_MAX_LIMIT-2)>; - }; - }; - }; - - cpu-1-0-lowf { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-sensors = <&tsens0 7>; - thermal-governor = "low_limits_floor"; - tracks-low; - trips { - cpu10_trip: cpu10-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_cdev { - trip = <&cpu10_trip>; - cooling-device = <&CPU0 1 1>; - }; - cpu1_cdev { - trip = <&cpu10_trip>; - cooling-device = <&CPU4 5 5>; - }; - cx_vdd_cdev { - trip = <&cpu10_trip>; - cooling-device = <&cx_cdev 0 0>; - }; - mx_vdd_cdev { - trip = <&cpu10_trip>; - cooling-device = <&mx_cdev 0 0>; - }; - ebi_vdd_cdev { - trip = <&cpu10_trip>; - cooling-device = <&ebi_cdev 0 0>; - }; - mmcx_vdd_cdev { - trip = <&cpu10_trip>; - cooling-device = <&mm_cx_cdev 0 0>; - }; - modem_vdd_cdev { - trip = <&cpu10_trip>; - cooling-device = <&modem_vdd 0 0>; - }; - adsp_vdd_cdev { - trip = <&cpu10_trip>; - cooling-device = <&adsp_vdd 0 0>; - }; - cdsp_vdd_cdev { - trip = <&cpu10_trip>; - cooling-device = <&cdsp_vdd 0 0>; - }; - slpi_vdd_cdev { - trip = <&cpu10_trip>; - cooling-device = <&slpi_vdd 0 0>; - }; - gpu_vdd_cdev { - trip = <&cpu10_trip>; - cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) - (THERMAL_MAX_LIMIT-2)>; - }; - }; - }; - - cpu-1-1-lowf { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-sensors = <&tsens0 8>; - thermal-governor = "low_limits_floor"; - tracks-low; - trips { - cpu11_trip: cpu11-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_cdev { - trip = <&cpu11_trip>; - cooling-device = <&CPU0 1 1>; - }; - cpu1_cdev { - trip = <&cpu11_trip>; - cooling-device = <&CPU4 5 5>; - }; - cx_vdd_cdev { - trip = <&cpu11_trip>; - cooling-device = <&cx_cdev 0 0>; - }; - mx_vdd_cdev { - trip = <&cpu11_trip>; - cooling-device = <&mx_cdev 0 0>; - }; - ebi_vdd_cdev { - trip = <&cpu11_trip>; - cooling-device = <&ebi_cdev 0 0>; - }; - mmcx_vdd_cdev { - trip = <&cpu11_trip>; - cooling-device = <&mm_cx_cdev 0 0>; - }; - modem_vdd_cdev { - trip = <&cpu11_trip>; - cooling-device = <&modem_vdd 0 0>; - }; - adsp_vdd_cdev { - trip = <&cpu11_trip>; - cooling-device = <&adsp_vdd 0 0>; - }; - cdsp_vdd_cdev { - trip = <&cpu11_trip>; - cooling-device = <&cdsp_vdd 0 0>; - }; - slpi_vdd_cdev { - trip = <&cpu11_trip>; - cooling-device = <&slpi_vdd 0 0>; - }; - gpu_vdd_cdev { - trip = <&cpu11_trip>; - cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) - (THERMAL_MAX_LIMIT-2)>; - }; - }; - }; - - cpu-1-2-lowf { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-sensors = <&tsens0 9>; - thermal-governor = "low_limits_floor"; - tracks-low; - trips { - cpu12_trip: cpu12-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_cdev { - trip = <&cpu12_trip>; - cooling-device = <&CPU0 1 1>; - }; - cpu1_cdev { - trip = <&cpu12_trip>; - cooling-device = <&CPU4 5 5>; - }; - cx_vdd_cdev { - trip = <&cpu12_trip>; - cooling-device = <&cx_cdev 0 0>; - }; - mx_vdd_cdev { - trip = <&cpu12_trip>; - cooling-device = <&mx_cdev 0 0>; - }; - ebi_vdd_cdev { - trip = <&cpu12_trip>; - cooling-device = <&ebi_cdev 0 0>; - }; - mmcx_vdd_cdev { - trip = <&cpu12_trip>; - cooling-device = <&mm_cx_cdev 0 0>; - }; - modem_vdd_cdev { - trip = <&cpu12_trip>; - cooling-device = <&modem_vdd 0 0>; - }; - adsp_vdd_cdev { - trip = <&cpu12_trip>; - cooling-device = <&adsp_vdd 0 0>; - }; - cdsp_vdd_cdev { - trip = <&cpu12_trip>; - cooling-device = <&cdsp_vdd 0 0>; - }; - slpi_vdd_cdev { - trip = <&cpu12_trip>; - cooling-device = <&slpi_vdd 0 0>; - }; - gpu_vdd_cdev { - trip = <&cpu12_trip>; - cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) - (THERMAL_MAX_LIMIT-2)>; - }; - }; - }; - - cpu-1-3-lowf { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-sensors = <&tsens0 10>; - thermal-governor = "low_limits_floor"; - tracks-low; - trips { - cpu13_trip: cpu13-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_cdev { - trip = <&cpu13_trip>; - cooling-device = <&CPU0 1 1>; - }; - cpu1_cdev { - trip = <&cpu13_trip>; - cooling-device = <&CPU4 5 5>; - }; - cx_vdd_cdev { - trip = <&cpu13_trip>; - cooling-device = <&cx_cdev 0 0>; - }; - mx_vdd_cdev { - trip = <&cpu13_trip>; - cooling-device = <&mx_cdev 0 0>; - }; - ebi_vdd_cdev { - trip = <&cpu13_trip>; - cooling-device = <&ebi_cdev 0 0>; - }; - mmcx_vdd_cdev { - trip = <&cpu13_trip>; - cooling-device = <&mm_cx_cdev 0 0>; - }; - modem_vdd_cdev { - trip = <&cpu13_trip>; - cooling-device = <&modem_vdd 0 0>; - }; - adsp_vdd_cdev { - trip = <&cpu13_trip>; - cooling-device = <&adsp_vdd 0 0>; - }; - cdsp_vdd_cdev { - trip = <&cpu13_trip>; - cooling-device = <&cdsp_vdd 0 0>; - }; - slpi_vdd_cdev { - trip = <&cpu13_trip>; - cooling-device = <&slpi_vdd 0 0>; - }; - gpu_vdd_cdev { - trip = <&cpu13_trip>; - cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) - (THERMAL_MAX_LIMIT-2)>; - }; - }; - }; - - cpu-1-4-lowf { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-sensors = <&tsens0 11>; - thermal-governor = "low_limits_floor"; - tracks-low; - trips { - cpu14_trip: cpu14-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_cdev { - trip = <&cpu14_trip>; - cooling-device = <&CPU0 1 1>; - }; - cpu1_cdev { - trip = <&cpu14_trip>; - cooling-device = <&CPU4 5 5>; - }; - cx_vdd_cdev { - trip = <&cpu14_trip>; - cooling-device = <&cx_cdev 0 0>; - }; - mx_vdd_cdev { - trip = <&cpu14_trip>; - cooling-device = <&mx_cdev 0 0>; - }; - ebi_vdd_cdev { - trip = <&cpu14_trip>; - cooling-device = <&ebi_cdev 0 0>; - }; - mmcx_vdd_cdev { - trip = <&cpu14_trip>; - cooling-device = <&mm_cx_cdev 0 0>; - }; - modem_vdd_cdev { - trip = <&cpu14_trip>; - cooling-device = <&modem_vdd 0 0>; - }; - adsp_vdd_cdev { - trip = <&cpu14_trip>; - cooling-device = <&adsp_vdd 0 0>; - }; - cdsp_vdd_cdev { - trip = <&cpu14_trip>; - cooling-device = <&cdsp_vdd 0 0>; - }; - slpi_vdd_cdev { - trip = <&cpu14_trip>; - cooling-device = <&slpi_vdd 0 0>; - }; - gpu_vdd_cdev { - trip = <&cpu14_trip>; - cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) - (THERMAL_MAX_LIMIT-2)>; - }; - }; - }; - - cpu-1-5-lowf { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-sensors = <&tsens0 12>; - thermal-governor = "low_limits_floor"; - tracks-low; - trips { - cpu15_trip: cpu15-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_cdev { - trip = <&cpu15_trip>; - cooling-device = <&CPU0 1 1>; - }; - cpu1_cdev { - trip = <&cpu15_trip>; - cooling-device = <&CPU4 5 5>; - }; - cx_vdd_cdev { - trip = <&cpu15_trip>; - cooling-device = <&cx_cdev 0 0>; - }; - mx_vdd_cdev { - trip = <&cpu15_trip>; - cooling-device = <&mx_cdev 0 0>; - }; - ebi_vdd_cdev { - trip = <&cpu15_trip>; - cooling-device = <&ebi_cdev 0 0>; - }; - mmcx_vdd_cdev { - trip = <&cpu15_trip>; - cooling-device = <&mm_cx_cdev 0 0>; - }; - modem_vdd_cdev { - trip = <&cpu15_trip>; - cooling-device = <&modem_vdd 0 0>; - }; - adsp_vdd_cdev { - trip = <&cpu15_trip>; - cooling-device = <&adsp_vdd 0 0>; - }; - cdsp_vdd_cdev { - trip = <&cpu15_trip>; - cooling-device = <&cdsp_vdd 0 0>; - }; - slpi_vdd_cdev { - trip = <&cpu15_trip>; - cooling-device = <&slpi_vdd 0 0>; - }; - gpu_vdd_cdev { - trip = <&cpu15_trip>; - cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) - (THERMAL_MAX_LIMIT-2)>; - }; - }; - }; - - cpu-1-6-lowf { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-sensors = <&tsens0 13>; - thermal-governor = "low_limits_floor"; - tracks-low; - trips { - cpu16_trip: cpu16-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_cdev { - trip = <&cpu16_trip>; - cooling-device = <&CPU0 1 1>; - }; - cpu1_cdev { - trip = <&cpu16_trip>; - cooling-device = <&CPU4 5 5>; - }; - cx_vdd_cdev { - trip = <&cpu16_trip>; - cooling-device = <&cx_cdev 0 0>; - }; - mx_vdd_cdev { - trip = <&cpu16_trip>; - cooling-device = <&mx_cdev 0 0>; - }; - ebi_vdd_cdev { - trip = <&cpu16_trip>; - cooling-device = <&ebi_cdev 0 0>; - }; - mmcx_vdd_cdev { - trip = <&cpu16_trip>; - cooling-device = <&mm_cx_cdev 0 0>; - }; - modem_vdd_cdev { - trip = <&cpu16_trip>; - cooling-device = <&modem_vdd 0 0>; - }; - adsp_vdd_cdev { - trip = <&cpu16_trip>; - cooling-device = <&adsp_vdd 0 0>; - }; - cdsp_vdd_cdev { - trip = <&cpu16_trip>; - cooling-device = <&cdsp_vdd 0 0>; - }; - slpi_vdd_cdev { - trip = <&cpu16_trip>; - cooling-device = <&slpi_vdd 0 0>; - }; - gpu_vdd_cdev { - trip = <&cpu16_trip>; - cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) - (THERMAL_MAX_LIMIT-2)>; - }; - }; - }; - - cpu-1-7-lowf { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-sensors = <&tsens0 14>; - thermal-governor = "low_limits_floor"; - tracks-low; - trips { - cpu17_trip: cpu17-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_cdev { - trip = <&cpu17_trip>; - cooling-device = <&CPU0 1 1>; - }; - cpu1_cdev { - trip = <&cpu17_trip>; - cooling-device = <&CPU4 5 5>; - }; - cx_vdd_cdev { - trip = <&cpu17_trip>; - cooling-device = <&cx_cdev 0 0>; - }; - mx_vdd_cdev { - trip = <&cpu17_trip>; - cooling-device = <&mx_cdev 0 0>; - }; - ebi_vdd_cdev { - trip = <&cpu17_trip>; - cooling-device = <&ebi_cdev 0 0>; - }; - mmcx_vdd_cdev { - trip = <&cpu17_trip>; - cooling-device = <&mm_cx_cdev 0 0>; - }; - modem_vdd_cdev { - trip = <&cpu17_trip>; - cooling-device = <&modem_vdd 0 0>; - }; - adsp_vdd_cdev { - trip = <&cpu17_trip>; - cooling-device = <&adsp_vdd 0 0>; - }; - cdsp_vdd_cdev { - trip = <&cpu17_trip>; - cooling-device = <&cdsp_vdd 0 0>; - }; - slpi_vdd_cdev { - trip = <&cpu17_trip>; - cooling-device = <&slpi_vdd 0 0>; - }; - gpu_vdd_cdev { - trip = <&cpu17_trip>; - cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) - (THERMAL_MAX_LIMIT-2)>; - }; - }; - }; - - gpuss-0-lowf { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-sensors = <&tsens0 15>; - thermal-governor = "low_limits_floor"; - tracks-low; - trips { - gpuss0_trip: gpuss0-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_cdev { - trip = <&gpuss0_trip>; - cooling-device = <&CPU0 1 1>; - }; - cpu1_cdev { - trip = <&gpuss0_trip>; - cooling-device = <&CPU4 5 5>; - }; - cx_vdd_cdev { - trip = <&gpuss0_trip>; - cooling-device = <&cx_cdev 0 0>; - }; - mx_vdd_cdev { - trip = <&gpuss0_trip>; - cooling-device = <&mx_cdev 0 0>; - }; - ebi_vdd_cdev { - trip = <&gpuss0_trip>; - cooling-device = <&ebi_cdev 0 0>; - }; - mmcx_vdd_cdev { - trip = <&gpuss0_trip>; - cooling-device = <&mm_cx_cdev 0 0>; - }; - modem_vdd_cdev { - trip = <&gpuss0_trip>; - cooling-device = <&modem_vdd 0 0>; - }; - adsp_vdd_cdev { - trip = <&gpuss0_trip>; - cooling-device = <&adsp_vdd 0 0>; - }; - cdsp_vdd_cdev { - trip = <&gpuss0_trip>; - cooling-device = <&cdsp_vdd 0 0>; - }; - slpi_vdd_cdev { - trip = <&gpuss0_trip>; - cooling-device = <&slpi_vdd 0 0>; - }; - gpu_vdd_cdev { - trip = <&gpuss0_trip>; - cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) - (THERMAL_MAX_LIMIT-2)>; - }; - }; - }; - - aoss-1-lowf { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-sensors = <&tsens1 0>; - thermal-governor = "low_limits_floor"; - tracks-low; - trips { - aoss1_trip: aoss1-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_cdev { - trip = <&aoss1_trip>; - cooling-device = <&CPU0 1 1>; - }; - cpu1_cdev { - trip = <&aoss1_trip>; - cooling-device = <&CPU4 5 5>; - }; - cx_vdd_cdev { - trip = <&aoss1_trip>; - cooling-device = <&cx_cdev 0 0>; - }; - mx_vdd_cdev { - trip = <&aoss1_trip>; - cooling-device = <&mx_cdev 0 0>; - }; - ebi_vdd_cdev { - trip = <&aoss1_trip>; - cooling-device = <&ebi_cdev 0 0>; - }; - mmcx_vdd_cdev { - trip = <&aoss1_trip>; - cooling-device = <&mm_cx_cdev 0 0>; - }; - modem_vdd_cdev { - trip = <&aoss1_trip>; - cooling-device = <&modem_vdd 0 0>; - }; - adsp_vdd_cdev { - trip = <&aoss1_trip>; - cooling-device = <&adsp_vdd 0 0>; - }; - cdsp_vdd_cdev { - trip = <&aoss1_trip>; - cooling-device = <&cdsp_vdd 0 0>; - }; - slpi_vdd_cdev { - trip = <&aoss1_trip>; - cooling-device = <&slpi_vdd 0 0>; - }; - gpu_vdd_cdev { - trip = <&aoss1_trip>; - cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) - (THERMAL_MAX_LIMIT-2)>; - }; - }; - }; - - cwlan-lowf { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-sensors = <&tsens1 1>; - thermal-governor = "low_limits_floor"; - tracks-low; - trips { - cwlan_trip: cwlan-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_cdev { - trip = <&cwlan_trip>; - cooling-device = <&CPU0 1 1>; - }; - cpu1_cdev { - trip = <&cwlan_trip>; - cooling-device = <&CPU4 5 5>; - }; - cx_vdd_cdev { - trip = <&cwlan_trip>; - cooling-device = <&cx_cdev 0 0>; - }; - mx_vdd_cdev { - trip = <&cwlan_trip>; - cooling-device = <&mx_cdev 0 0>; - }; - ebi_vdd_cdev { - trip = <&cwlan_trip>; - cooling-device = <&ebi_cdev 0 0>; - }; - mmcx_vdd_cdev { - trip = <&cwlan_trip>; - cooling-device = <&mm_cx_cdev 0 0>; - }; - modem_vdd_cdev { - trip = <&cwlan_trip>; - cooling-device = <&modem_vdd 0 0>; - }; - adsp_vdd_cdev { - trip = <&cwlan_trip>; - cooling-device = <&adsp_vdd 0 0>; - }; - cdsp_vdd_cdev { - trip = <&cwlan_trip>; - cooling-device = <&cdsp_vdd 0 0>; - }; - slpi_vdd_cdev { - trip = <&cwlan_trip>; - cooling-device = <&slpi_vdd 0 0>; - }; - gpu_vdd_cdev { - trip = <&cwlan_trip>; - cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) - (THERMAL_MAX_LIMIT-2)>; - }; - }; - }; - - video-lowf { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-sensors = <&tsens1 2>; - thermal-governor = "low_limits_floor"; - tracks-low; - trips { - video_trip: video-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_cdev { - trip = <&video_trip>; - cooling-device = <&CPU0 1 1>; - }; - cpu1_cdev { - trip = <&video_trip>; - cooling-device = <&CPU4 5 5>; - }; - cx_vdd_cdev { - trip = <&video_trip>; - cooling-device = <&cx_cdev 0 0>; - }; - mx_vdd_cdev { - trip = <&video_trip>; - cooling-device = <&mx_cdev 0 0>; - }; - ebi_vdd_cdev { - trip = <&video_trip>; - cooling-device = <&ebi_cdev 0 0>; - }; - mmcx_vdd_cdev { - trip = <&video_trip>; - cooling-device = <&mm_cx_cdev 0 0>; - }; - modem_vdd_cdev { - trip = <&video_trip>; - cooling-device = <&modem_vdd 0 0>; - }; - adsp_vdd_cdev { - trip = <&video_trip>; - cooling-device = <&adsp_vdd 0 0>; - }; - cdsp_vdd_cdev { - trip = <&video_trip>; - cooling-device = <&cdsp_vdd 0 0>; - }; - slpi_vdd_cdev { - trip = <&video_trip>; - cooling-device = <&slpi_vdd 0 0>; - }; - gpu_vdd_cdev { - trip = <&video_trip>; - cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) - (THERMAL_MAX_LIMIT-2)>; - }; - }; - }; - - ddr-lowf { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-sensors = <&tsens1 3>; - thermal-governor = "low_limits_floor"; - tracks-low; - trips { - ddr_trip: ddr-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_cdev { - trip = <&ddr_trip>; - cooling-device = <&CPU0 1 1>; - }; - cpu1_cdev { - trip = <&ddr_trip>; - cooling-device = <&CPU4 5 5>; - }; - cx_vdd_cdev { - trip = <&ddr_trip>; - cooling-device = <&cx_cdev 0 0>; - }; - mx_vdd_cdev { - trip = <&ddr_trip>; - cooling-device = <&mx_cdev 0 0>; - }; - ebi_vdd_cdev { - trip = <&ddr_trip>; - cooling-device = <&ebi_cdev 0 0>; - }; - mmcx_vdd_cdev { - trip = <&ddr_trip>; - cooling-device = <&mm_cx_cdev 0 0>; - }; - modem_vdd_cdev { - trip = <&ddr_trip>; - cooling-device = <&modem_vdd 0 0>; - }; - adsp_vdd_cdev { - trip = <&ddr_trip>; - cooling-device = <&adsp_vdd 0 0>; - }; - cdsp_vdd_cdev { - trip = <&ddr_trip>; - cooling-device = <&cdsp_vdd 0 0>; - }; - slpi_vdd_cdev { - trip = <&ddr_trip>; - cooling-device = <&slpi_vdd 0 0>; - }; - gpu_vdd_cdev { - trip = <&ddr_trip>; - cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) - (THERMAL_MAX_LIMIT-2)>; - }; - }; - }; - - q6-hvx-lowf { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-sensors = <&tsens1 4>; - thermal-governor = "low_limits_floor"; - tracks-low; - trips { - q6_trip: q6-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_cdev { - trip = <&q6_trip>; - cooling-device = <&CPU0 1 1>; - }; - cpu1_cdev { - trip = <&q6_trip>; - cooling-device = <&CPU4 5 5>; - }; - cx_vdd_cdev { - trip = <&q6_trip>; - cooling-device = <&cx_cdev 0 0>; - }; - mx_vdd_cdev { - trip = <&q6_trip>; - cooling-device = <&mx_cdev 0 0>; - }; - ebi_vdd_cdev { - trip = <&q6_trip>; - cooling-device = <&ebi_cdev 0 0>; - }; - mmcx_vdd_cdev { - trip = <&q6_trip>; - cooling-device = <&mm_cx_cdev 0 0>; - }; - modem_vdd_cdev { - trip = <&q6_trip>; - cooling-device = <&modem_vdd 0 0>; - }; - adsp_vdd_cdev { - trip = <&q6_trip>; - cooling-device = <&adsp_vdd 0 0>; - }; - cdsp_vdd_cdev { - trip = <&q6_trip>; - cooling-device = <&cdsp_vdd 0 0>; - }; - slpi_vdd_cdev { - trip = <&q6_trip>; - cooling-device = <&slpi_vdd 0 0>; - }; - gpu_vdd_cdev { - trip = <&q6_trip>; - cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) - (THERMAL_MAX_LIMIT-2)>; - }; - }; - }; - - camera-lowf { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-sensors = <&tsens1 5>; - thermal-governor = "low_limits_floor"; - tracks-low; - trips { - camera_trip: camera-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_cdev { - trip = <&camera_trip>; - cooling-device = <&CPU0 1 1>; - }; - cpu1_cdev { - trip = <&camera_trip>; - cooling-device = <&CPU4 5 5>; - }; - cx_vdd_cdev { - trip = <&camera_trip>; - cooling-device = <&cx_cdev 0 0>; - }; - mx_vdd_cdev { - trip = <&camera_trip>; - cooling-device = <&mx_cdev 0 0>; - }; - ebi_vdd_cdev { - trip = <&camera_trip>; - cooling-device = <&ebi_cdev 0 0>; - }; - mmcx_vdd_cdev { - trip = <&camera_trip>; - cooling-device = <&mm_cx_cdev 0 0>; - }; - modem_vdd_cdev { - trip = <&camera_trip>; - cooling-device = <&modem_vdd 0 0>; - }; - adsp_vdd_cdev { - trip = <&camera_trip>; - cooling-device = <&adsp_vdd 0 0>; - }; - cdsp_vdd_cdev { - trip = <&camera_trip>; - cooling-device = <&cdsp_vdd 0 0>; - }; - slpi_vdd_cdev { - trip = <&camera_trip>; - cooling-device = <&slpi_vdd 0 0>; - }; - gpu_vdd_cdev { - trip = <&camera_trip>; - cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) - (THERMAL_MAX_LIMIT-2)>; - }; - }; - }; - - cmpss-lowf { + cpu-1-4-lowf { polling-delay-passive = <0>; polling-delay = <0>; - thermal-sensors = <&tsens1 6>; + thermal-sensors = <&tsens0 11>; thermal-governor = "low_limits_floor"; tracks-low; trips { - cmpss_trip: cmpss-trip { + cpu14_trip: cpu14-trip { temperature = <5000>; hysteresis = <5000>; type = "passive"; @@ -1872,61 +508,61 @@ }; cooling-maps { cpu0_cdev { - trip = <&cmpss_trip>; + trip = <&cpu14_trip>; cooling-device = <&CPU0 1 1>; }; cpu1_cdev { - trip = <&cmpss_trip>; + trip = <&cpu14_trip>; cooling-device = <&CPU4 5 5>; }; cx_vdd_cdev { - trip = <&cmpss_trip>; + trip = <&cpu14_trip>; cooling-device = <&cx_cdev 0 0>; }; mx_vdd_cdev { - trip = <&cmpss_trip>; + trip = <&cpu14_trip>; cooling-device = <&mx_cdev 0 0>; }; ebi_vdd_cdev { - trip = <&cmpss_trip>; + trip = <&cpu14_trip>; cooling-device = <&ebi_cdev 0 0>; }; mmcx_vdd_cdev { - trip = <&cmpss_trip>; + trip = <&cpu14_trip>; cooling-device = <&mm_cx_cdev 0 0>; }; modem_vdd_cdev { - trip = <&cmpss_trip>; + trip = <&cpu14_trip>; cooling-device = <&modem_vdd 0 0>; }; adsp_vdd_cdev { - trip = <&cmpss_trip>; + trip = <&cpu14_trip>; cooling-device = <&adsp_vdd 0 0>; }; cdsp_vdd_cdev { - trip = <&cmpss_trip>; + trip = <&cpu14_trip>; cooling-device = <&cdsp_vdd 0 0>; }; slpi_vdd_cdev { - trip = <&cmpss_trip>; + trip = <&cpu14_trip>; cooling-device = <&slpi_vdd 0 0>; }; gpu_vdd_cdev { - trip = <&cmpss_trip>; + trip = <&cpu14_trip>; cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) (THERMAL_MAX_LIMIT-2)>; }; }; }; - mdm-core-lowf { + cpu-1-7-lowf { polling-delay-passive = <0>; polling-delay = <0>; - thermal-sensors = <&tsens1 7>; + thermal-sensors = <&tsens0 14>; thermal-governor = "low_limits_floor"; tracks-low; trips { - mdm_trip: mdm-trip { + cpu17_trip: cpu17-trip { temperature = <5000>; hysteresis = <5000>; type = "passive"; @@ -1934,61 +570,61 @@ }; cooling-maps { cpu0_cdev { - trip = <&mdm_trip>; + trip = <&cpu17_trip>; cooling-device = <&CPU0 1 1>; }; cpu1_cdev { - trip = <&mdm_trip>; + trip = <&cpu17_trip>; cooling-device = <&CPU4 5 5>; }; cx_vdd_cdev { - trip = <&mdm_trip>; + trip = <&cpu17_trip>; cooling-device = <&cx_cdev 0 0>; }; mx_vdd_cdev { - trip = <&mdm_trip>; + trip = <&cpu17_trip>; cooling-device = <&mx_cdev 0 0>; }; ebi_vdd_cdev { - trip = <&mdm_trip>; + trip = <&cpu17_trip>; cooling-device = <&ebi_cdev 0 0>; }; mmcx_vdd_cdev { - trip = <&mdm_trip>; + trip = <&cpu17_trip>; cooling-device = <&mm_cx_cdev 0 0>; }; modem_vdd_cdev { - trip = <&mdm_trip>; + trip = <&cpu17_trip>; cooling-device = <&modem_vdd 0 0>; }; adsp_vdd_cdev { - trip = <&mdm_trip>; + trip = <&cpu17_trip>; cooling-device = <&adsp_vdd 0 0>; }; cdsp_vdd_cdev { - trip = <&mdm_trip>; + trip = <&cpu17_trip>; cooling-device = <&cdsp_vdd 0 0>; }; slpi_vdd_cdev { - trip = <&mdm_trip>; + trip = <&cpu17_trip>; cooling-device = <&slpi_vdd 0 0>; }; gpu_vdd_cdev { - trip = <&mdm_trip>; + trip = <&cpu17_trip>; cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) (THERMAL_MAX_LIMIT-2)>; }; }; }; - npu-lowf { + gpuss-0-lowf { polling-delay-passive = <0>; polling-delay = <0>; - thermal-sensors = <&tsens1 8>; + thermal-sensors = <&tsens0 15>; thermal-governor = "low_limits_floor"; tracks-low; trips { - npu_trip: npu-trip { + gpuss0_trip: gpuss0-trip { temperature = <5000>; hysteresis = <5000>; type = "passive"; @@ -1996,61 +632,61 @@ }; cooling-maps { cpu0_cdev { - trip = <&npu_trip>; + trip = <&gpuss0_trip>; cooling-device = <&CPU0 1 1>; }; cpu1_cdev { - trip = <&npu_trip>; + trip = <&gpuss0_trip>; cooling-device = <&CPU4 5 5>; }; cx_vdd_cdev { - trip = <&npu_trip>; + trip = <&gpuss0_trip>; cooling-device = <&cx_cdev 0 0>; }; mx_vdd_cdev { - trip = <&npu_trip>; + trip = <&gpuss0_trip>; cooling-device = <&mx_cdev 0 0>; }; ebi_vdd_cdev { - trip = <&npu_trip>; + trip = <&gpuss0_trip>; cooling-device = <&ebi_cdev 0 0>; }; mmcx_vdd_cdev { - trip = <&npu_trip>; + trip = <&gpuss0_trip>; cooling-device = <&mm_cx_cdev 0 0>; }; modem_vdd_cdev { - trip = <&npu_trip>; + trip = <&gpuss0_trip>; cooling-device = <&modem_vdd 0 0>; }; adsp_vdd_cdev { - trip = <&npu_trip>; + trip = <&gpuss0_trip>; cooling-device = <&adsp_vdd 0 0>; }; cdsp_vdd_cdev { - trip = <&npu_trip>; + trip = <&gpuss0_trip>; cooling-device = <&cdsp_vdd 0 0>; }; slpi_vdd_cdev { - trip = <&npu_trip>; + trip = <&gpuss0_trip>; cooling-device = <&slpi_vdd 0 0>; }; gpu_vdd_cdev { - trip = <&npu_trip>; + trip = <&gpuss0_trip>; cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) (THERMAL_MAX_LIMIT-2)>; }; }; }; - mdm-vec-lowf { + camera-lowf { polling-delay-passive = <0>; polling-delay = <0>; - thermal-sensors = <&tsens1 9>; + thermal-sensors = <&tsens1 5>; thermal-governor = "low_limits_floor"; tracks-low; trips { - mdmv_trip: mdmv-trip { + camera_trip: camera-trip { temperature = <5000>; hysteresis = <5000>; type = "passive"; @@ -2058,47 +694,47 @@ }; cooling-maps { cpu0_cdev { - trip = <&mdmv_trip>; + trip = <&camera_trip>; cooling-device = <&CPU0 1 1>; }; cpu1_cdev { - trip = <&mdmv_trip>; + trip = <&camera_trip>; cooling-device = <&CPU4 5 5>; }; cx_vdd_cdev { - trip = <&mdmv_trip>; + trip = <&camera_trip>; cooling-device = <&cx_cdev 0 0>; }; mx_vdd_cdev { - trip = <&mdmv_trip>; + trip = <&camera_trip>; cooling-device = <&mx_cdev 0 0>; }; ebi_vdd_cdev { - trip = <&mdmv_trip>; + trip = <&camera_trip>; cooling-device = <&ebi_cdev 0 0>; }; mmcx_vdd_cdev { - trip = <&mdmv_trip>; + trip = <&camera_trip>; cooling-device = <&mm_cx_cdev 0 0>; }; modem_vdd_cdev { - trip = <&mdmv_trip>; + trip = <&camera_trip>; cooling-device = <&modem_vdd 0 0>; }; adsp_vdd_cdev { - trip = <&mdmv_trip>; + trip = <&camera_trip>; cooling-device = <&adsp_vdd 0 0>; }; cdsp_vdd_cdev { - trip = <&mdmv_trip>; + trip = <&camera_trip>; cooling-device = <&cdsp_vdd 0 0>; }; slpi_vdd_cdev { - trip = <&mdmv_trip>; + trip = <&camera_trip>; cooling-device = <&slpi_vdd 0 0>; }; gpu_vdd_cdev { - trip = <&mdmv_trip>; + trip = <&camera_trip>; cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) (THERMAL_MAX_LIMIT-2)>; }; @@ -2167,68 +803,6 @@ }; }; - gpuss-1-lowf { - polling-delay-passive = <0>; - polling-delay = <0>; - thermal-governor = "low_limits_floor"; - thermal-sensors = <&tsens1 11>; - tracks-low; - trips { - gpuss1_trip: gpuss1-trip { - temperature = <5000>; - hysteresis = <5000>; - type = "passive"; - }; - }; - cooling-maps { - cpu0_cdev { - trip = <&gpuss1_trip>; - cooling-device = <&CPU0 1 1>; - }; - cpu1_cdev { - trip = <&gpuss1_trip>; - cooling-device = <&CPU4 5 5>; - }; - cx_vdd_cdev { - trip = <&gpuss1_trip>; - cooling-device = <&cx_cdev 0 0>; - }; - mx_vdd_cdev { - trip = <&gpuss1_trip>; - cooling-device = <&mx_cdev 0 0>; - }; - ebi_vdd_cdev { - trip = <&gpuss1_trip>; - cooling-device = <&ebi_cdev 0 0>; - }; - mmcx_vdd_cdev { - trip = <&gpuss1_trip>; - cooling-device = <&mm_cx_cdev 0 0>; - }; - modem_vdd_cdev { - trip = <&gpuss1_trip>; - cooling-device = <&modem_vdd 0 0>; - }; - adsp_vdd_cdev { - trip = <&gpuss1_trip>; - cooling-device = <&adsp_vdd 0 0>; - }; - cdsp_vdd_cdev { - trip = <&gpuss1_trip>; - cooling-device = <&cdsp_vdd 0 0>; - }; - slpi_vdd_cdev { - trip = <&gpuss1_trip>; - cooling-device = <&slpi_vdd 0 0>; - }; - gpu_vdd_cdev { - trip = <&gpuss1_trip>; - cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) - (THERMAL_MAX_LIMIT-2)>; - }; - }; - }; - gpuss-max-step { polling-delay-passive = <10>; polling-delay = <100>; diff --git a/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi b/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi index 1351a7e09ac5528cb8b63b0baca040169d29ef0d..2feaf41ec2562a09c5abad9efa2bf6f62c509847 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-usb.dtsi @@ -295,7 +295,7 @@ USB3_DP_PCS_EQ_CONFIG1 0x0d 0 USB3_DP_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL 0xf8 0 USB3_DP_PCS_USB3_RXEQTRAINING_DFE_TIME_S2 0x07 0 - USB3_DP_PCS_EQ_CONFIG5 0x52 0 + USB3_DP_PCS_EQ_CONFIG5 0x02 0 0xffffffff 0xffffffff 0x00>; qcom,qmp-phy-reg-offset = diff --git a/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi b/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi index 39e6c20295ae1ef580751301d51434c0a38ece7e..c2e7c67148938bb25dda63ad5dce20cae7dbf1de 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi @@ -418,7 +418,7 @@ 1785600 128 >; idle-cost-data = < - 22 18 14 12 + 18 14 12 >; }; @@ -443,7 +443,7 @@ 2419200 1022 >; idle-cost-data = < - 100 80 60 40 + 80 60 40 >; }; @@ -471,7 +471,7 @@ 2841600 1427 >; idle-cost-data = < - 130 110 90 70 + 110 90 70 >; }; @@ -497,7 +497,7 @@ 1785600 17 >; idle-cost-data = < - 4 3 2 1 + 3 2 1 >; }; @@ -522,7 +522,7 @@ 2419200 106 >; idle-cost-data = < - 4 3 2 1 + 3 2 1 >; }; @@ -550,7 +550,7 @@ 2841600 180 >; idle-cost-data = < - 4 3 2 1 + 3 2 1 >; }; }; @@ -562,6 +562,9 @@ /* Updated chip ID */ qcom,chipid = <0x06040001>; + /* Power level to start throttling */ + qcom,throttle-pwrlevel = <2>; + /* Updated Bus Scale Settings */ qcom,msm-bus,num-cases = <12>; @@ -668,6 +671,18 @@ reg-names = "kgsl_gmu_reg", "kgsl_gmu_pdc_cfg", "kgsl_gmu_pdc_seq"; + + qcom,gpu-acd-table { + /* Corresponds to levels in the GPU perf table */ + qcom,acd-enable-by-level = <0x1e>; + qcom,acd-stride = <0x2>; + qcom,acd-num-levels = <0x4>; + + qcom,acd-data = <0xa02d5ffd 0x00007611 + 0xa02d5ffd 0x00006911 + 0xa02d5ffd 0x00006111 + 0x802d5ffd 0x00005411>; + }; }; /* NPU overrides */ @@ -910,6 +925,18 @@ }; &cpu4_cpu_l3_latmon { + qcom,core-dev-table = + < 300000 300000000 >, + < 825600 614400000 >, + < 1171200 806400000 >, + < 1401600 998400000 >, + < 1708800 1267200000 >, + < 2016000 1344000000 >, + < 2419200 1536000000 >, + < 2841600 1612800000 >; +}; + +&cpu7_cpu_l3_latmon { qcom,core-dev-table = < 300000 300000000 >, < 825600 614400000 >, diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 9d733c1865ce135836c766633e1d153c9b3f8b6a..88d12728e2a7e15e1368b7152d4416cda026e6ca 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -435,7 +435,7 @@ 1267200 88 >; idle-cost-data = < - 22 18 14 12 + 18 14 12 >; }; @@ -460,7 +460,7 @@ 2016000 807 >; idle-cost-data = < - 100 80 60 40 + 80 60 40 >; }; @@ -485,7 +485,7 @@ 2054400 960 >; idle-cost-data = < - 130 110 90 70 + 110 90 70 >; }; @@ -504,7 +504,7 @@ 1267200 10 >; idle-cost-data = < - 4 3 2 1 + 3 2 1 >; }; @@ -530,7 +530,7 @@ >; idle-cost-data = < - 4 3 2 1 + 3 2 1 >; }; @@ -555,7 +555,7 @@ 2054400 140 >; idle-cost-data = < - 4 3 2 1 + 3 2 1 >; }; }; /* energy-costs */ @@ -915,6 +915,16 @@ interrupt-parent = <&intc>; }; + gict: gict@17a20000 { + compatible = "arm,gic-600-erp"; + reg = <0x17a20000 0x10000>; + reg-names = "gict-base"; + interrupt-config = <46 17>; + interrupt-names = "gict-fault", "gict-err"; + interrupts = , + ; + }; + pdc: interrupt-controller@0xb220000{ compatible = "qcom,pdc-sm8150"; reg = <0xb220000 0x400>; @@ -1134,7 +1144,7 @@ cpu4_cpu_l3_latmon: qcom,cpu4-cpu-l3-latmon { compatible = "qcom,arm-memlat-mon"; - qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>; + qcom,cpulist = <&CPU4 &CPU5 &CPU6>; qcom,target-dev = <&cpu4_cpu_l3_lat>; qcom,cachemiss-ev = <0x17>; qcom,core-dev-table = @@ -1146,6 +1156,27 @@ < 2016000 1344000000 >; }; + cpu7_cpu_l3_lat: qcom,cpu7-cpu-l3-lat { + compatible = "devfreq-simple-dev"; + clock-names = "devfreq_clk"; + clocks = <&clock_cpucc L3_CLUSTER2_VOTE_CLK>; + governor = "performance"; + }; + + cpu7_cpu_l3_latmon: qcom,cpu7-cpu-l3-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU7>; + qcom,target-dev = <&cpu7_cpu_l3_lat>; + qcom,cachemiss-ev = <0x17>; + qcom,core-dev-table = + < 300000 300000000 >, + < 768000 576000000 >, + < 1152000 768000000 >, + < 1344000 960000000 >, + < 1689600 1228800000 >, + < 2016000 1344000000 >; + }; + cpu0_cpu_llcc_lat: qcom,cpu0-cpu-llcc-lat { compatible = "qcom,devbw"; governor = "performance"; @@ -1262,13 +1293,6 @@ interrupts = <1 5 4>; }; - dsu_pmu@0 { - compatible = "arm,dsu-pmu"; - interrupts = ; - cpus = <&CPU0>, <&CPU1>, <&CPU2>, <&CPU3>, - <&CPU4>, <&CPU5>, <&CPU6>, <&CPU7>; - }; - qcom,msm-imem@146bf000 { compatible = "qcom,msm-imem"; reg = <0x146bf000 0x1000>; @@ -1324,6 +1348,12 @@ qcom,rtb-size = <0x100000>; }; + qcom,aop-ddr-msgs { + compatible = "qcom,aop-ddr-msgs"; + mboxes = <&qmp_aop 0>; + mbox-name = "restart-ddr-mbox"; + }; + qcom,mpm2-sleep-counter@0xc221000 { compatible = "qcom,mpm2-sleep-counter"; reg = <0xc221000 0x1000>; @@ -1497,7 +1527,7 @@ reg-names = "osm_l3_base", "osm_pwrcl_base", "osm_perfcl_base", "osm_perfpcl_base"; l3-devs = <&cpu0_cpu_l3_lat &cpu4_cpu_l3_lat &cdsp_cdsp_l3_lat - &msm_gpu>; + &msm_gpu &cpu7_cpu_l3_lat>; #clock-cells = <1>; }; @@ -2271,7 +2301,7 @@ <0 0>, <0 0>, <37500000 300000000>, - <75000000 300000000>, + <37500000 300000000>, <0 0>, <0 0>, <0 0>, @@ -2357,7 +2387,7 @@ msm_fastrpc: qcom,msm_fastrpc { compatible = "qcom,msm-fastrpc-compute"; qcom,fastrpc-adsp-audio-pdr; - qcom,rpc-latency-us = <611>; + qcom,rpc-latency-us = <235>; qcom,msm_fastrpc_compute_cb1 { compatible = "qcom,msm-fastrpc-compute-cb"; @@ -3109,10 +3139,10 @@ dcc: dcc_v2@10a2000 { compatible = "qcom,dcc-v2"; reg = <0x10a2000 0x1000>, - <0x10ae000 0x2000>; + <0x10ad000 0x3000>; reg-names = "dcc-base", "dcc-ram-base"; - dcc-ram-offset = <0x6000>; + dcc-ram-offset = <0x5000>; qcom,curr-link-list = <3>; qcom,link-list = , @@ -3513,6 +3543,7 @@ ipa_hw: qcom,ipa@1e00000 { compatible = "qcom,ipa"; + mboxes = <&qmp_aop 0>; reg = <0x1e00000 0x34000>, <0x1e04000 0x28000>; reg-names = "ipa-base", "gsi-base"; @@ -3635,7 +3666,7 @@ qcom,wlan-ramdump-dynamic = <0x400000>; mhi,max-channels = <30>; - mhi,timeout = <1000>; + mhi,timeout = <10000>; mhi_chan@0 { reg = <0>; diff --git a/arch/arm64/boot/dts/qcom/trinket-gdsc.dtsi b/arch/arm64/boot/dts/qcom/trinket-gdsc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..8738bb5d9326e06a0dd3f7fa8a60b58941fba7ff --- /dev/null +++ b/arch/arm64/boot/dts/qcom/trinket-gdsc.dtsi @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + /* GDSCs in Global CC */ + camss_cpp_gdsc: qcom,gdsc@14560bc { + compatible = "regulator-fixed"; + regulator-name = "cam_cpp_gdsc"; + reg = <0x14560bc 0x4>; + status = "disabled"; + }; + + camss_top_gdsc: qcom,gdsc@145607c { + compatible = "regulator-fixed"; + regulator-name = "camss_top_gdsc"; + reg = <0x145607c 0x4>; + status = "disabled"; + }; + + camss_vfe0_gdsc: qcom,gdsc@1454004 { + compatible = "regulator-fixed"; + regulator-name = "camss_vfe0_gdsc"; + reg = <0x1454004 0x4>; + status = "disabled"; + }; + + camss_vfe1_gdsc: qcom,gdsc@145403c { + compatible = "regulator-fixed"; + regulator-name = "camss_vfe1_gdsc"; + reg = <0x145403c 0x4>; + status = "disabled"; + }; + + ufs_phy_gdsc: qcom,gdsc@1445004 { + compatible = "regulator-fixed"; + regulator-name = "ufs_phy_gdsc"; + reg = <0x1445004 0x4>; + status = "disabled"; + }; + + usb30_prim_gdsc: qcom,gdsc@141a004 { + compatible = "regulator-fixed"; + regulator-name = "usb30_prim_gdsc"; + reg = <0x141a004 0x4>; + status = "disabled"; + }; + + /* GDSCs in Display CC */ + mdss_core_gdsc: qcom,gdsc@5f03000 { + compatible = "regulator-fixed"; + regulator-name = "mdss_core_gdsc"; + reg = <0x5f03000 0x4>; + qcom,support-hw-trigger; + status = "disabled"; + proxy-supply = <&mdss_core_gdsc>; + qcom,proxy-consumer-enable; + }; + + /* GDSCs in Graphics CC */ + gpu_cx_hw_ctrl: syscon@5991540 { + compatible = "syscon"; + reg = <0x5991540 0x4>; + }; + + gpu_cx_gdsc: qcom,gdsc@599106c { + compatible = "regulator-fixed"; + regulator-name = "gpu_cx_gdsc"; + reg = <0x599106c 0x4>; + hw-ctrl-addr = <&gpu_cx_hw_ctrl>; + qcom,no-status-check-on-disable; + qcom,gds-timeout = <500>; + qcom,clk-dis-wait-val = <8>; + status = "disabled"; + }; + + gpu_gx_gdsc: qcom,gdsc@599100c { + compatible = "regulator-fixed"; + regulator-name = "gpu_gx_gdsc"; + reg = <0x599100c 0x4>; + status = "disabled"; + }; + + /* GDSCs in Video CC */ + vcodec0_gdsc: qcom,gdsc@5b00874 { + compatible = "regulator-fixed"; + regulator-name = "vcodec0_gdsc"; + reg = <0x5b00874 0x4>; + status = "disabled"; + }; + + venus_gdsc: qcom,gdsc@5b00814 { + compatible = "regulator-fixed"; + regulator-name = "venus_gdsc"; + reg = <0x5b00814 0x4>; + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/trinket-ion.dtsi b/arch/arm64/boot/dts/qcom/trinket-ion.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..7c35e6991afe6f9660aadef6bee721f8475d546d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/trinket-ion.dtsi @@ -0,0 +1,35 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + qcom,ion { + compatible = "qcom,msm-ion"; + #address-cells = <1>; + #size-cells = <0>; + + system_heap: qcom,ion-heap@25 { + reg = <25>; + qcom,ion-heap-type = "SYSTEM"; + }; + + qcom,ion-heap@27 { /* QSEECOM HEAP */ + reg = <27>; + memory-region = <&qseecom_mem>; + qcom,ion-heap-type = "DMA"; + }; + + qcom,ion-heap@9 { + reg = <9>; + qcom,ion-heap-type = "SYSTEM_SECURE"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/trinket-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/trinket-pinctrl.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..052cf8e9d8343b299865a0978fb5795b43048dc7 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/trinket-pinctrl.dtsi @@ -0,0 +1,25 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +&soc { + tlmm: pinctrl@400000 { + compatible = "qcom,trinket-pinctrl"; + reg = <0x400000 0xc00000>; + interrupts = <0 227 0>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/trinket-rumi-overlay.dts b/arch/arm64/boot/dts/qcom/trinket-rumi-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..5b34eacac89b5579da858e0b9694b825bfcafdc8 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/trinket-rumi-overlay.dts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include +#include "trinket-rumi.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. TRINKET RUMI"; + compatible = "qcom,trinket-rumi", "qcom,trinket", "qcom,rumi"; + qcom,msm-id = <394 0x0>; + qcom,board-id = <15 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/trinket-rumi.dts b/arch/arm64/boot/dts/qcom/trinket-rumi.dts new file mode 100644 index 0000000000000000000000000000000000000000..fb74e3e1df9cf5452ee9971c4aecdef857592c12 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/trinket-rumi.dts @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/memreserve/ 0x90000000 0x00000100; + +#include "trinket.dtsi" +#include "trinket-rumi.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. TRINKET RUMI"; + compatible = "qcom,trinket-rumi", "qcom,trinket", "qcom,rumi"; + qcom,board-id = <15 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/trinket-rumi.dtsi b/arch/arm64/boot/dts/qcom/trinket-rumi.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..87612484431ef29b7f8d36a3e875eefb0afb4901 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/trinket-rumi.dtsi @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + timer { + clock-frequency = <800000>; + }; + + timer@f120000 { + clock-frequency = <800000>; + }; + + wdog: qcom,wdt@f017000{ + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/trinket.dts b/arch/arm64/boot/dts/qcom/trinket.dts new file mode 100644 index 0000000000000000000000000000000000000000..29ece99394ee58f9f50200eaf3a29dd2817be004 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/trinket.dts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "trinket.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. TRINKET SoC"; + compatible = "qcom,trinket"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/trinket.dtsi b/arch/arm64/boot/dts/qcom/trinket.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..1ea08e7417d9254bb0ec34f6aa4f0fc5a2a690c5 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/trinket.dtsi @@ -0,0 +1,964 @@ +/* + * Copyright (c) 2018, The Linux Foundation.All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "skeleton64.dtsi" +#include + +/ { + model = "Qualcomm Technologies, Inc. TRINKET"; + compatible = "qcom,trinket"; + qcom,msm-id = <394 0x0>; + interrupt-parent = <&intc>; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x0>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + L2_0: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + }; + L1_I_0: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + + L1_D_0: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + + L1_TLB_0: l1-tlb { + qcom,dump-size = <0x2800>; + }; + }; + + CPU1: cpu@1 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x1>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + + L1_I_1: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + + L1_D_1: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + + L1_TLB_1: l1-tlb { + qcom,dump-size = <0x2800>; + }; + }; + + CPU2: cpu@2 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x2>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + + L1_I_2: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + + L1_D_2: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + + L1_TLB_2: l1-tlb { + qcom,dump-size = <0x2800>; + }; + }; + + CPU3: cpu@3 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x3>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + + L1_I_3: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + + L1_D_3: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + + L1_TLB_3: l1-tlb { + qcom,dump-size = <0x2800>; + }; + }; + + CPU4: cpu@100 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x100>; + enable-method = "psci"; + next-level-cache = <&L2_1>; + L2_1: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + }; + + L1_I_100: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + + L1_D_100: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + + L1_TLB_100: l1-tlb { + qcom,dump-size = <0x4800>; + }; + }; + + CPU5: cpu@101 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x101>; + enable-method = "psci"; + next-level-cache = <&L2_1>; + + L1_I_101: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + + L1_D_101: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + + L1_TLB_101: l1-tlb { + qcom,dump-size = <0x4800>; + }; + }; + + CPU6: cpu@102 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x102>; + enable-method = "psci"; + next-level-cache = <&L2_1>; + + L1_I_102: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + + L1_D_102: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + + L1_TLB_102: l1-tlb { + qcom,dump-size = <0x4800>; + }; + }; + + CPU7: cpu@103 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x103>; + enable-method = "psci"; + next-level-cache = <&L2_1>; + + L1_I_103: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + + L1_D_103: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + + L1_TLB_103: l1-tlb { + qcom,dump-size = <0x4800>; + }; + }; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + + core1 { + cpu = <&CPU1>; + }; + + core2 { + cpu = <&CPU2>; + }; + + core3 { + cpu = <&CPU3>; + }; + }; + + cluster1 { + core0 { + cpu = <&CPU4>; + }; + + core1 { + cpu = <&CPU5>; + }; + + core2 { + cpu = <&CPU6>; + }; + + core3 { + cpu = <&CPU7>; + }; + }; + }; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + chosen { + bootargs = "rcupdate.rcu_expedited=1 rcu_nocbs=0-7"; + }; + + soc: soc { }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + hyp_region: hyp_region@25700000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x25700000 0 0x600000>; + }; + + xbl_aop_mem: xbl_aop_mem@25e00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x25e00000 0x0 0x140000>; + }; + + sec_apps_mem: sec_apps_region@25fff000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x25fff000 0x0 0x1000>; + }; + + smem_region: smem@26000000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x26000000 0x0 0x200000>; + }; + + removed_region: removed_region@26200000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x26200000 0 0x2d00000>; + }; + + pil_camera_mem: camera_region@2ab00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x2ab00000 0 0x500000>; + }; + + pil_modem_mem: modem_region@2b000000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x2b000000 0 0x7e00000>; + }; + + pil_video_mem: pil_video_region@32e00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x32e00000 0 0x500000>; + }; + + wlan_msa_mem: wlan_msa_region@33300000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x33300000 0 0x100000>; + }; + + pil_cdsp_mem: cdsp_regions@33400000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x33400000 0 0x800000>; + }; + + pil_adsp_mem: pil_adsp_region@33c00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x33c00000 0 0x1e00000>; + }; + + pil_ipa_fw_mem: ips_fw_region@35a00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x35a00000 0 0x10000>; + }; + + pil_ipa_gsi_mem: ipa_gsi_region@35a10000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x35a10000 0 0x5000>; + }; + + pil_gpu_mem: gpu_region@35a15000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x35a15000 0 0x2000>; + }; + + qseecom_mem: qseecom_region@3e400000 { + compatible = "shared-dma-pool"; + no-map; + reg = <0 0x3e400000 0 0x1400000>; + }; + + /* global autoconfigured region for contiguous allocations */ + linux,cma { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0x2000000>; + linux,cma-default; + }; + }; +}; + +&soc { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0 0xffffffff>; + compatible = "simple-bus"; + + intc: interrupt-controller@f200000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + interrupt-controller; + #redistributor-regions = <1>; + redistributor-stride = <0x0 0x20000>; + reg = <0xf200000 0x10000>, /* GICD */ + <0xf300000 0x100000>; /* GICR * 8 */ + interrupts = <1 9 4>; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <1 1 0xf08>, + <1 2 0xf08>, + <1 3 0xf08>, + <1 0 0xf08>; + clock-frequency = <19200000>; + }; + + timer@f120000 { + #address-cells = <1>; + #size-cells = <1>; + ranges; + compatible = "arm,armv7-timer-mem"; + reg = <0xf120000 0x1000>; + clock-frequency = <19200000>; + + frame@f121000 { + frame-number = <0>; + interrupts = <0 8 0x4>, + <0 7 0x4>; + reg = <0xf121000 0x1000>, + <0xf122000 0x1000>; + }; + + frame@f123000 { + frame-number = <1>; + interrupts = <0 9 0x4>; + reg = <0xf123000 0x1000>; + status = "disabled"; + }; + + frame@f124000 { + frame-number = <2>; + interrupts = <0 10 0x4>; + reg = <0xf124000 0x1000>; + status = "disabled"; + }; + + frame@f125000 { + frame-number = <3>; + interrupts = <0 11 0x4>; + reg = <0xf125000 0x1000>; + status = "disabled"; + }; + + frame@f126000 { + frame-number = <4>; + interrupts = <0 12 0x4>; + reg = <0xf126000 0x1000>; + status = "disabled"; + }; + + frame@f127000 { + frame-number = <5>; + interrupts = <0 13 0x4>; + reg = <0xf127000 0x1000>; + status = "disabled"; + }; + + frame@f128000 { + frame-number = <6>; + interrupts = <0 14 0x4>; + reg = <0xf128000 0x1000>; + status = "disabled"; + }; + }; + + qcom,msm-imem@c125000 { + compatible = "qcom,msm-imem"; + reg = <0xc125000 0x1000>; + ranges = <0x0 0xc125000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + mem_dump_table@10 { + compatible = "qcom,msm-imem-mem_dump_table"; + reg = <0x10 8>; + }; + + restart_reason@65c { + compatible = "qcom,msm-imem-restart_reason"; + reg = <0x65c 4>; + }; + + dload_type@1c { + compatible = "qcom,msm-imem-dload-type"; + reg = <0x1c 0x4>; + }; + + boot_stats@6b0 { + compatible = "qcom,msm-imem-boot_stats"; + reg = <0x6b0 32>; + }; + + kaslr_offset@6d0 { + compatible = "qcom,msm-imem-kaslr_offset"; + reg = <0x6d0 12>; + }; + + pil@94c { + compatible = "qcom,msm-imem-pil"; + reg = <0x94c 200>; + }; + + diag_dload@c8 { + compatible = "qcom,msm-imem-diag-dload"; + reg = <0xc8 200>; + }; + }; + + restart@440b000 { + compatible = "qcom,pshold"; + reg = <0x440b000 0x4>, + <0x03d3000 0x4>; + reg-names = "pshold-base", "tcsr-boot-misc-detect"; + }; + + qcom,mpm2-sleep-counter@4403000 { + compatible = "qcom,mpm2-sleep-counter"; + reg = <0x4403000 0x1000>; + clock-frequency = <32768>; + }; + + qcom,msm-rtb { + compatible = "qcom,msm-rtb"; + qcom,rtb-size = <0x100000>; + }; + + cpu_pmu: cpu-pmu { + compatible = "arm,armv8-pmuv3"; + qcom,irq-is-percpu; + interrupts = <1 6 4>; + }; + + eud: qcom,msm-eud@1610000 { + compatible = "qcom,msm-eud"; + interrupt-names = "eud_irq"; + interrupts = ; + reg = <0x1610000 0x2000>; + reg-names = "eud_base"; + status = "ok"; + }; + + wdog: qcom,wdt@f017000 { + compatible = "qcom,msm-watchdog"; + reg = <0xf017000 0x1000>; + reg-names = "wdt-base"; + interrupts = <0 3 0>, <0 4 0>; + qcom,bark-time = <11000>; + qcom,pet-time = <9360>; + qcom,ipi-ping; + qcom,wakeup-enable; + qcom,scandump-sizes = <0x40000>; + }; + + qcom,chd_silver { + compatible = "qcom,core-hang-detect"; + label = "silver"; + qcom,threshold-arr = <0xf1880b0 0xf1980b0 + 0xf1a80b0 0xf1b80b0>; + qcom,config-arr = <0xf1880b8 0xf1980b8 + 0xf1a80b8 0xf1b80b8>; + }; + + qcom,chd_gold { + compatible = "qcom,core-hang-detect"; + label = "gold"; + qcom,threshold-arr = <0xf0880b0 0xf0980b0 + 0xf0a80b0 0xf0b80b0>; + qcom,config-arr = <0xf0880b8 0xf0980b8 + 0xf0a80b8 0xf0b80b8>; + }; + + qcom,ghd { + compatible = "qcom,gladiator-hang-detect"; + qcom,threshold-arr = <0x0f1d141c 0x0f1d1420 + 0x0f1d1424 0x0f1d1428 + 0x0f1d142c 0x0f1d1430>; + qcom,config-reg = <0x0f1d1434>; + }; + + cpuss_dump: cpuss_dump { + compatible = "qcom,cpuss-dump"; + qcom,l1_i_cache0 { + qcom,dump-node = <&L1_I_0>; + qcom,dump-id = <0x60>; + }; + qcom,l1_i_cache1 { + qcom,dump-node = <&L1_I_1>; + qcom,dump-id = <0x61>; + }; + qcom,l1_i_cache2 { + qcom,dump-node = <&L1_I_2>; + qcom,dump-id = <0x62>; + }; + qcom,l1_i_cache3 { + qcom,dump-node = <&L1_I_3>; + qcom,dump-id = <0x63>; + }; + qcom,l1_i_cache100 { + qcom,dump-node = <&L1_I_100>; + qcom,dump-id = <0x64>; + }; + qcom,l1_i_cache101 { + qcom,dump-node = <&L1_I_101>; + qcom,dump-id = <0x65>; + }; + qcom,l1_i_cache102 { + qcom,dump-node = <&L1_I_102>; + qcom,dump-id = <0x66>; + }; + qcom,l1_i_cache103 { + qcom,dump-node = <&L1_I_103>; + qcom,dump-id = <0x67>; + }; + qcom,l1_d_cache0 { + qcom,dump-node = <&L1_D_0>; + qcom,dump-id = <0x80>; + }; + qcom,l1_d_cache1 { + qcom,dump-node = <&L1_D_1>; + qcom,dump-id = <0x81>; + }; + qcom,l1_d_cache2 { + qcom,dump-node = <&L1_D_2>; + qcom,dump-id = <0x82>; + }; + qcom,l1_d_cache3 { + qcom,dump-node = <&L1_D_3>; + qcom,dump-id = <0x83>; + }; + qcom,l1_d_cache100 { + qcom,dump-node = <&L1_D_100>; + qcom,dump-id = <0x84>; + }; + qcom,l1_d_cache101 { + qcom,dump-node = <&L1_D_101>; + qcom,dump-id = <0x85>; + }; + qcom,l1_d_cache102 { + qcom,dump-node = <&L1_D_102>; + qcom,dump-id = <0x86>; + }; + qcom,l1_d_cache103 { + qcom,dump-node = <&L1_D_103>; + qcom,dump-id = <0x87>; + }; + qcom,l1_tlb_dump0 { + qcom,dump-node = <&L1_TLB_0>; + qcom,dump-id = <0x20>; + }; + qcom,l1_tlb_dump1 { + qcom,dump-node = <&L1_TLB_1>; + qcom,dump-id = <0x21>; + }; + qcom,l1_tlb_dump2 { + qcom,dump-node = <&L1_TLB_2>; + qcom,dump-id = <0x22>; + }; + qcom,l1_tlb_dump3 { + qcom,dump-node = <&L1_TLB_3>; + qcom,dump-id = <0x23>; + }; + qcom,l1_tlb_dump100 { + qcom,dump-node = <&L1_TLB_100>; + qcom,dump-id = <0x24>; + }; + qcom,l1_tlb_dump101 { + qcom,dump-node = <&L1_TLB_101>; + qcom,dump-id = <0x25>; + }; + qcom,l1_tlb_dump102 { + qcom,dump-node = <&L1_TLB_102>; + qcom,dump-id = <0x26>; + }; + qcom,l1_tlb_dump103 { + qcom,dump-node = <&L1_TLB_103>; + qcom,dump-id = <0x27>; + }; + }; + + tcsr_mutex_block: syscon@00340000 { + compatible = "syscon"; + reg = <0x00340000 0x20000>; + }; + + tcsr_mutex: hwlock { + compatible = "qcom,tcsr-mutex"; + syscon = <&tcsr_mutex_block 0 0x1000>; + #hwlock-cells = <1>; + }; + + smem: qcom,smem { + compatible = "qcom,smem"; + memory-region = <&smem_region>; + hwlocks = <&tcsr_mutex 3>; + }; + + rpm_msg_ram: memory@045F0000 { + compatible = "qcom,rpm-msg-ram"; + reg = <0x045F0000 0x8000>; + }; + + apcs_glb: mailbox@0F111000 { + compatible = "qcom,trinket-apcs-hmss-global"; + reg = <0x0F111000 0x1000>; + + #mbox-cells = <1>; + }; + + rpm-glink { + compatible = "qcom,glink-rpm"; + interrupts = ; + qcom,rpm-msg-ram = <&rpm_msg_ram>; + mboxes = <&apcs_glb 0>; + + qcom,rpm_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_modem>, + <&glink_adsp>, + <&glink_cdsp>; + }; + + }; + + qcom,glink { + compatible = "qcom,glink"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + glink_modem: modem { + qcom,remote-pid = <1>; + transport = "smem"; + mboxes = <&apcs_glb 12>; + mbox-names = "mpss_smem"; + interrupts = ; + + label = "modem"; + qcom,glink-label = "mpss"; + + qcom,modem_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + qcom,intents = <0x64 64>; + }; + + qcom,modem_ds { + qcom,glink-channels = "DS"; + qcom,intents = <0x4000 2>; + }; + + qcom,modem_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_adsp>, + <&glink_cdsp>; + }; + }; + + glink_adsp: adsp { + qcom,remote-pid = <2>; + transport = "smem"; + mboxes = <&apcs_glb 8>; + mbox-names = "adsp_smem"; + interrupts = ; + + label = "adsp"; + qcom,glink-label = "lpass"; + + qcom,adsp_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,apr_tal_rpmsg { + qcom,glink-channels = "apr_audio_svc"; + qcom,intents = <0x200 20>; + }; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + qcom,intents = <0x64 64>; + }; + + qcom,adsp_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_modem>, + <&glink_cdsp>; + }; + }; + + glink_cdsp: cdsp { + qcom,remote-pid = <5>; + transport = "smem"; + mboxes = <&apcs_glb 28>; + mbox-names = "cdsp_smem"; + interrupts = ; + + label = "cdsp"; + qcom,glink-label = "cdsp"; + + qcom,cdsp_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + qcom,intents = <0x64 64>; + }; + + qcom,cdsp_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_modem>, + <&glink_adsp>; + }; + }; + + glink_spi_xprt_wdsp: wdsp { + qcom,remote-pid = <10>; + transport = "spi"; + tx-descriptors = <0x12000 0x12004>; + rx-descriptors = <0x1200c 0x12010>; + + qcom,wdsp_ctrl { + qcom,glink-channels = "g_glink_ctrl"; + qcom,intents = <0x400 1>; + }; + + qcom,wdsp_ild { + qcom,glink-channels = + "g_glink_persistent_data_ild"; + }; + + qcom,wdsp_nild { + qcom,glink-channels = + "g_glink_persistent_data_nild"; + }; + + qcom,wdsp_data { + qcom,glink-channels = "g_glink_audio_data"; + qcom,intents = <0x1000 2>; + }; + }; + }; + + qcom,glinkpkt { + compatible = "qcom,glinkpkt"; + + qcom,glinkpkt-at-mdm0 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DS"; + qcom,glinkpkt-dev-name = "at_mdm0"; + }; + + qcom,glinkpkt-apr-apps2 { + qcom,glinkpkt-edge = "adsp"; + qcom,glinkpkt-ch-name = "apr_apps2"; + qcom,glinkpkt-dev-name = "apr_apps2"; + }; + + qcom,glinkpkt-data40-cntl { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA40_CNTL"; + qcom,glinkpkt-dev-name = "smdcntl8"; + }; + + qcom,glinkpkt-data1 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA1"; + qcom,glinkpkt-dev-name = "smd7"; + }; + + qcom,glinkpkt-data4 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA4"; + qcom,glinkpkt-dev-name = "smd8"; + }; + + qcom,glinkpkt-data11 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA11"; + qcom,glinkpkt-dev-name = "smd11"; + }; + }; + + qcom,smp2p_sleepstate { + compatible = "qcom,smp2p-sleepstate"; + qcom,smem-states = <&sleepstate_smp2p_out 0>; + interrupt-parent = <&sleepstate_smp2p_in>; + interrupts = <0 0>; + interrupt-names = "smp2p-sleepstate-in"; + }; + + qcom,smp2p-modem { + compatible = "qcom,smp2p"; + qcom,smem = <435>, <428>; + interrupts = ; + mboxes = <&apcs_glb 14>; + qcom,local-pid = <0>; + qcom,remote-pid = <1>; + + modem_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + modem_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + qcom,smp2p-adsp { + compatible = "qcom,smp2p"; + qcom,smem = <443>, <429>; + interrupts = ; + mboxes = <&apcs_glb 10>; + qcom,local-pid = <0>; + qcom,remote-pid = <2>; + + adsp_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + adsp_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + sleepstate_smp2p_out: sleepstate-out { + qcom,entry-name = "sleepstate"; + #qcom,smem-state-cells = <1>; + }; + + sleepstate_smp2p_in: qcom,sleepstate-in { + qcom,entry-name = "sleepstate_see"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + qcom,smp2p-cdsp { + compatible = "qcom,smp2p"; + qcom,smem = <94>, <432>; + interrupts = ; + mboxes = <&apcs_glb 30>; + qcom,local-pid = <0>; + qcom,remote-pid = <5>; + + cdsp_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + cdsp_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +}; +#include "trinket-pinctrl.dtsi" +#include "trinket-ion.dtsi" diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi index d70e409e2b0cbd7a2a1d07f2c84e86475fe8fd02..efac2202b16ec10301a40dea1b10ef464bad8e1a 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi @@ -331,7 +331,7 @@ reg = <0x0 0xff120000 0x0 0x100>; interrupts = ; clocks = <&cru SCLK_UART1>, <&cru PCLK_UART1>; - clock-names = "sclk_uart", "pclk_uart"; + clock-names = "baudclk", "apb_pclk"; dmas = <&dmac 4>, <&dmac 5>; #dma-cells = <2>; pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi b/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi index a29c279b6e8e4c484b14c77047d1b8436103f6b3..dba6f0ff810639c3f22f43f744c896617243562b 100644 --- a/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi +++ b/arch/arm64/boot/dts/socionext/uniphier-ld20.dtsi @@ -55,6 +55,7 @@ clocks = <&sys_clk 32>; enable-method = "psci"; operating-points-v2 = <&cluster0_opp>; + #cooling-cells = <2>; }; cpu2: cpu@100 { @@ -73,6 +74,7 @@ clocks = <&sys_clk 33>; enable-method = "psci"; operating-points-v2 = <&cluster1_opp>; + #cooling-cells = <2>; }; }; diff --git a/arch/arm64/configs/sa8155-perf_defconfig b/arch/arm64/configs/sa8155-perf_defconfig deleted file mode 120000 index 8fb0cc34e9acb07e55393536d8145670168b41ed..0000000000000000000000000000000000000000 --- a/arch/arm64/configs/sa8155-perf_defconfig +++ /dev/null @@ -1 +0,0 @@ -vendor/sa8155-perf_defconfig \ No newline at end of file diff --git a/arch/arm64/configs/sa8155_defconfig b/arch/arm64/configs/sa8155_defconfig deleted file mode 120000 index 005726151a08f9f0d914e8fd263611cb2ade3b59..0000000000000000000000000000000000000000 --- a/arch/arm64/configs/sa8155_defconfig +++ /dev/null @@ -1 +0,0 @@ -vendor/sa8155_defconfig \ No newline at end of file diff --git a/arch/arm64/configs/vendor/qcs405-perf_defconfig b/arch/arm64/configs/vendor/qcs405-perf_defconfig index 1e270380e07933eb776d214e6016d6681482e6c9..676c66996b9bde71d013a7c505d8e5202b705a37 100644 --- a/arch/arm64/configs/vendor/qcs405-perf_defconfig +++ b/arch/arm64/configs/vendor/qcs405-perf_defconfig @@ -1,3 +1,4 @@ +CONFIG_POSIX_MQUEUE=y CONFIG_AUDIT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y @@ -203,6 +204,7 @@ CONFIG_ZRAM=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y CONFIG_QPNP_MISC=y CONFIG_SCSI=y @@ -244,6 +246,7 @@ CONFIG_CLD_LL_CORE=y CONFIG_INPUT_EVDEV=y CONFIG_INPUT_EVBUG=m CONFIG_INPUT_KEYRESET=y +CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_JOYSTICK=y CONFIG_JOYSTICK_XPAD=y @@ -314,6 +317,8 @@ CONFIG_FB=y CONFIG_FB_MSM=y CONFIG_FB_MSM_MDSS=y CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS_HDMI_PANEL=y +CONFIG_FB_MSM_MDSS_SPI_PANEL=y CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_SOUND=y @@ -349,6 +354,7 @@ CONFIG_USB_DWC3=y CONFIG_USB_DWC3_MSM=y CONFIG_USB_SERIAL=y CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_TYPEC_MUX_NXP5150A=y CONFIG_NOP_USB_XCEIV=y CONFIG_MSM_SNPS_FEMTO_PHY=y CONFIG_USB_MSM_SSPHY=y @@ -370,6 +376,7 @@ CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y @@ -445,6 +452,7 @@ CONFIG_QCOM_KGSL=y CONFIG_QTI_MPM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_MSM_TZ_LOG=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT3_FS=y @@ -463,6 +471,7 @@ CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ASCII=y CONFIG_NLS_ISO8859_1=y CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y CONFIG_PAGE_OWNER=y CONFIG_MAGIC_SYSRQ=y CONFIG_PAGE_POISONING=y @@ -492,3 +501,6 @@ CONFIG_CRYPTO_CTR=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_STACK_HASH_ORDER_SHIFT=12 diff --git a/arch/arm64/configs/vendor/qcs405_defconfig b/arch/arm64/configs/vendor/qcs405_defconfig index 49c699275890abdea4c50c545ecf1c0012354cc5..3d6f1e194eb2a1b467f5d9bf9ad04c9e1e9bd078 100644 --- a/arch/arm64/configs/vendor/qcs405_defconfig +++ b/arch/arm64/configs/vendor/qcs405_defconfig @@ -1,3 +1,4 @@ +CONFIG_POSIX_MQUEUE=y CONFIG_AUDIT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y @@ -256,6 +257,7 @@ CONFIG_CLD_LL_CORE=y CONFIG_INPUT_EVDEV=y CONFIG_INPUT_EVBUG=m CONFIG_INPUT_KEYRESET=y +CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_JOYSTICK=y CONFIG_JOYSTICK_XPAD=y @@ -330,6 +332,7 @@ CONFIG_FB=y CONFIG_FB_MSM=y CONFIG_FB_MSM_MDSS=y CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS_HDMI_PANEL=y CONFIG_FB_MSM_MDSS_SPI_PANEL=y CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y @@ -367,6 +370,7 @@ CONFIG_USB_DWC3=y CONFIG_USB_DWC3_MSM=y CONFIG_USB_SERIAL=y CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_TYPEC_MUX_NXP5150A=y CONFIG_NOP_USB_XCEIV=y CONFIG_MSM_SNPS_FEMTO_PHY=y CONFIG_USB_MSM_SSPHY=y @@ -391,6 +395,7 @@ CONFIG_MMC_CLKGATE=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y @@ -556,3 +561,5 @@ CONFIG_CRYPTO_CTR=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y diff --git a/arch/arm64/configs/vendor/sa8155-perf_defconfig b/arch/arm64/configs/vendor/sa8155-perf_defconfig index aadc30a38b098cbdc19329d65b19ab7d40b034e4..81c3270f6849a803a347991b6223fc1e545851be 100644 --- a/arch/arm64/configs/vendor/sa8155-perf_defconfig +++ b/arch/arm64/configs/vendor/sa8155-perf_defconfig @@ -76,6 +76,7 @@ CONFIG_SETEND_EMULATION=y CONFIG_RANDOMIZE_BASE=y # CONFIG_EFI is not set CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_COMPAT=y CONFIG_PM_AUTOSLEEP=y diff --git a/arch/arm64/configs/vendor/sa8155_defconfig b/arch/arm64/configs/vendor/sa8155_defconfig index d1495301aad2d9d8aadba0f30d558993f371efa6..258973144d72f4f3108622b52c969cd74afd6d6a 100644 --- a/arch/arm64/configs/vendor/sa8155_defconfig +++ b/arch/arm64/configs/vendor/sa8155_defconfig @@ -82,6 +82,7 @@ CONFIG_SETEND_EMULATION=y # CONFIG_ARM64_VHE is not set CONFIG_RANDOMIZE_BASE=y CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_COMPAT=y CONFIG_PM_AUTOSLEEP=y diff --git a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig index 73d68b566c76b493517f79b5d063052cad354422..9f1aca1baad6415e7c217ef3987447b15779ea98 100644 --- a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig @@ -18,6 +18,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y +CONFIG_BLK_CGROUP=y CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_FREEZER=y CONFIG_CPUSETS=y @@ -52,6 +53,7 @@ CONFIG_MODULE_SIG=y CONFIG_MODULE_SIG_FORCE=y CONFIG_MODULE_SIG_SHA512=y CONFIG_PARTITION_ADVANCED=y +CONFIG_CFQ_GROUP_IOSCHED=y CONFIG_ARCH_QCOM=y CONFIG_ARCH_SM6150=y CONFIG_ARCH_SDMMAGPIE=y @@ -103,10 +105,12 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_SYN_COOKIES=y CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y +CONFIG_INET_UDP_DIAG=y CONFIG_INET_DIAG_DESTROY=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y @@ -168,6 +172,7 @@ CONFIG_NETFILTER_XT_MATCH_QTAGUID=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=y CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y @@ -203,6 +208,7 @@ CONFIG_IP6_NF_MANGLE=y CONFIG_IP6_NF_RAW=y CONFIG_BRIDGE_NF_EBTABLES=y CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_IP_SCTP=y CONFIG_L2TP=y CONFIG_L2TP_V3=y CONFIG_L2TP_IP=y @@ -230,6 +236,8 @@ CONFIG_NET_ACT_SKBEDIT=y CONFIG_QRTR=y CONFIG_QRTR_SMD=y CONFIG_SOCKEV_NLMCAST=y +CONFIG_CAN=y +CONFIG_QTI_CAN=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y @@ -246,10 +254,12 @@ CONFIG_ZRAM=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_HDCP_QSEECOM=y CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y CONFIG_MEMORY_STATE_TIME=y CONFIG_QPNP_MISC=y +CONFIG_FPR_FPC=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -273,6 +283,8 @@ CONFIG_TUN=y CONFIG_SKY2=y CONFIG_RMNET=y CONFIG_SMSC911X=y +CONFIG_AT803X_PHY=y +CONFIG_MICREL_PHY=y CONFIG_PPP=y CONFIG_PPP_BSDCOMP=y CONFIG_PPP_DEFLATE=y @@ -293,6 +305,7 @@ CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ST=y CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y CONFIG_TOUCHSCREEN_HIMAX_I2C=y CONFIG_TOUCHSCREEN_HIMAX_INCELL=y @@ -313,6 +326,7 @@ CONFIG_INPUT_UINPUT=y CONFIG_SERIAL_MSM_GENI=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y +# CONFIG_DEVPORT is not set CONFIG_DIAG_CHAR=y CONFIG_MSM_FASTCVPD=y CONFIG_MSM_ADSPRPC=y @@ -328,6 +342,7 @@ CONFIG_PM8150_PMIC_SIMULATOR=y CONFIG_PM8150B_PMIC_SIMULATOR=y CONFIG_PM8150L_PMIC_SIMULATOR=y CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_PTP_1588_CLOCK=y CONFIG_PINCTRL_SX150X=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y CONFIG_PINCTRL_SDMMAGPIE=y @@ -368,6 +383,7 @@ CONFIG_REGULATOR_RPMH=y CONFIG_REGULATOR_STUB=y CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_VIDEO_ADV_DEBUG=y @@ -379,6 +395,9 @@ CONFIG_MSM_VIDC_GOVERNORS=y CONFIG_MSM_SDE_ROTATOR=y CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y CONFIG_MSM_NPU=y +CONFIG_DVB_MPQ=m +CONFIG_DVB_MPQ_DEMUX=m +CONFIG_DVB_MPQ_SW=y CONFIG_DRM=y CONFIG_DRM_MSM_REGISTER_LOGGING=y CONFIG_DRM_SDE_EVTLOG_DEBUG=y @@ -511,6 +530,7 @@ CONFIG_MSM_GCC_SDMMAGPIE=y CONFIG_MSM_VIDEOCC_SDMMAGPIE=y CONFIG_MSM_NPUCC_SDMMAGPIE=y CONFIG_MSM_GPUCC_SDMMAGPIE=y +CONFIG_MSM_DEBUGCC_SDMMAGPIE=y CONFIG_HWSPINLOCK=y CONFIG_HWSPINLOCK_QCOM=y CONFIG_QCOM_APCS_IPC=y diff --git a/arch/arm64/configs/vendor/sdmsteppe_defconfig b/arch/arm64/configs/vendor/sdmsteppe_defconfig index ed422d551b209f96c47dbdf1238ab5a7b0f92ea4..e3b10348d508f95823ce84f38562d513b83773f1 100644 --- a/arch/arm64/configs/vendor/sdmsteppe_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe_defconfig @@ -17,6 +17,8 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y +CONFIG_BLK_CGROUP=y +CONFIG_DEBUG_BLK_CGROUP=y CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_FREEZER=y CONFIG_CPUSETS=y @@ -54,6 +56,7 @@ CONFIG_MODULE_SIG_SHA512=y # CONFIG_BLK_DEV_BSG is not set CONFIG_PARTITION_ADVANCED=y # CONFIG_IOSCHED_DEADLINE is not set +CONFIG_CFQ_GROUP_IOSCHED=y CONFIG_ARCH_QCOM=y CONFIG_ARCH_SM6150=y CONFIG_ARCH_SDMMAGPIE=y @@ -70,6 +73,7 @@ CONFIG_ZSMALLOC=y CONFIG_SECCOMP=y # CONFIG_UNMAP_KERNEL_AT_EL0 is not set # CONFIG_HARDEN_BRANCH_PREDICTOR is not set +CONFIG_PRINT_VMEMLAYOUT=y CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_CP15_BARRIER_EMULATION=y @@ -107,10 +111,12 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_SYN_COOKIES=y CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y +CONFIG_INET_UDP_DIAG=y CONFIG_INET_DIAG_DESTROY=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y @@ -172,6 +178,7 @@ CONFIG_NETFILTER_XT_MATCH_QTAGUID=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=y CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y @@ -207,6 +214,7 @@ CONFIG_IP6_NF_MANGLE=y CONFIG_IP6_NF_RAW=y CONFIG_BRIDGE_NF_EBTABLES=y CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_IP_SCTP=y CONFIG_L2TP=y CONFIG_L2TP_DEBUGFS=y CONFIG_L2TP_V3=y @@ -236,6 +244,8 @@ CONFIG_DNS_RESOLVER=y CONFIG_QRTR=y CONFIG_QRTR_SMD=y CONFIG_SOCKEV_NLMCAST=y +CONFIG_CAN=y +CONFIG_QTI_CAN=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y @@ -253,10 +263,12 @@ CONFIG_ZRAM=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_HDCP_QSEECOM=y CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y CONFIG_MEMORY_STATE_TIME=y CONFIG_QPNP_MISC=y +CONFIG_FPR_FPC=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -280,7 +292,8 @@ CONFIG_BONDING=y CONFIG_DUMMY=y CONFIG_TUN=y CONFIG_RMNET=y -CONFIG_PHYLIB=y +CONFIG_AT803X_PHY=y +CONFIG_MICREL_PHY=y CONFIG_PPP=y CONFIG_PPP_BSDCOMP=y CONFIG_PPP_DEFLATE=y @@ -293,6 +306,7 @@ CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y +CONFIG_USB_USBNET=y CONFIG_WIL6210=m CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CLD_LL_CORE=y @@ -301,6 +315,7 @@ CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_JOYSTICK=y CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ST=y CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y CONFIG_TOUCHSCREEN_HIMAX_I2C=y CONFIG_TOUCHSCREEN_HIMAX_INCELL=y @@ -324,6 +339,7 @@ CONFIG_SERIAL_DEV_BUS=y CONFIG_TTY_PRINTK=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y +# CONFIG_DEVPORT is not set CONFIG_DIAG_CHAR=y CONFIG_MSM_FASTCVPD=y CONFIG_MSM_ADSPRPC=y @@ -339,6 +355,7 @@ CONFIG_PM8150_PMIC_SIMULATOR=y CONFIG_PM8150B_PMIC_SIMULATOR=y CONFIG_PM8150L_PMIC_SIMULATOR=y CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_PTP_1588_CLOCK=y CONFIG_PINCTRL_SX150X=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y CONFIG_PINCTRL_SDMMAGPIE=y @@ -379,6 +396,7 @@ CONFIG_REGULATOR_RPMH=y CONFIG_REGULATOR_STUB=y CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_VIDEO_ADV_DEBUG=y @@ -390,6 +408,9 @@ CONFIG_MSM_VIDC_GOVERNORS=y CONFIG_MSM_SDE_ROTATOR=y CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y CONFIG_MSM_NPU=y +CONFIG_DVB_MPQ=m +CONFIG_DVB_MPQ_DEMUX=m +CONFIG_DVB_MPQ_SW=y CONFIG_DRM=y CONFIG_DRM_MSM_REGISTER_LOGGING=y CONFIG_DRM_SDE_EVTLOG_DEBUG=y @@ -487,6 +508,7 @@ CONFIG_RTC_DRV_QPNP=y CONFIG_DMADEVICES=y CONFIG_QCOM_GPI_DMA=y CONFIG_QCOM_GPI_DMA_DEBUG=y +CONFIG_DEBUG_DMA_BUF_REF=y CONFIG_UIO=y CONFIG_UIO_MSM_SHAREDMEM=y CONFIG_STAGING=y @@ -529,6 +551,7 @@ CONFIG_MSM_GCC_SDMMAGPIE=y CONFIG_MSM_VIDEOCC_SDMMAGPIE=y CONFIG_MSM_NPUCC_SDMMAGPIE=y CONFIG_MSM_GPUCC_SDMMAGPIE=y +CONFIG_MSM_DEBUGCC_SDMMAGPIE=y CONFIG_HWSPINLOCK=y CONFIG_HWSPINLOCK_QCOM=y CONFIG_QCOM_APCS_IPC=y @@ -651,6 +674,7 @@ CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y CONFIG_PRINTK_TIME=y CONFIG_DYNAMIC_DEBUG=y +CONFIG_DEBUG_MODULE_LOAD_INFO=y CONFIG_DEBUG_INFO=y CONFIG_PAGE_OWNER=y CONFIG_PAGE_OWNER_ENABLE_DEFAULT=y @@ -680,7 +704,6 @@ CONFIG_PANIC_ON_SCHED_BUG=y CONFIG_PANIC_ON_RT_THROTTLING=y CONFIG_SCHEDSTATS=y CONFIG_SCHED_STACK_END_CHECK=y -# CONFIG_DEBUG_PREEMPT is not set CONFIG_DEBUG_SPINLOCK=y CONFIG_DEBUG_MUTEXES=y CONFIG_DEBUG_ATOMIC_SLEEP=y @@ -698,6 +721,7 @@ CONFIG_IPC_LOGGING=y CONFIG_QCOM_RTB=y CONFIG_QCOM_RTB_SEPARATE_CPUS=y CONFIG_FUNCTION_TRACER=y +CONFIG_PREEMPTIRQ_EVENTS=y CONFIG_IRQSOFF_TRACER=y CONFIG_PREEMPT_TRACER=y CONFIG_BLK_DEV_IO_TRACE=y diff --git a/arch/arm64/configs/vendor/sm8150-perf_defconfig b/arch/arm64/configs/vendor/sm8150-perf_defconfig index 3daa53ecab0db3113841395433f2819c6f29846c..ab0081ef32ac886b8fdcbefbac99c03d3ec82434 100644 --- a/arch/arm64/configs/vendor/sm8150-perf_defconfig +++ b/arch/arm64/configs/vendor/sm8150-perf_defconfig @@ -60,6 +60,7 @@ CONFIG_ARCH_QCOM=y CONFIG_ARCH_SM8150=y CONFIG_PCI=y CONFIG_PCI_MSM=y +CONFIG_PCI_MSM_MSI=y CONFIG_SCHED_MC=y CONFIG_NR_CPUS=8 CONFIG_PREEMPT=y @@ -83,6 +84,7 @@ CONFIG_RANDOMIZE_BASE=y # CONFIG_EFI is not set CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y +CONFIG_KRYO_PMU_WORKAROUND=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_COMPAT=y CONFIG_PM_AUTOSLEEP=y @@ -111,10 +113,12 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_SYN_COOKIES=y CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y +CONFIG_INET_UDP_DIAG=y CONFIG_INET_DIAG_DESTROY=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y @@ -176,6 +180,7 @@ CONFIG_NETFILTER_XT_MATCH_QTAGUID=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=y CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y @@ -211,6 +216,7 @@ CONFIG_IP6_NF_MANGLE=y CONFIG_IP6_NF_RAW=y CONFIG_BRIDGE_NF_EBTABLES=y CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_IP_SCTP=y CONFIG_L2TP=y CONFIG_L2TP_V3=y CONFIG_L2TP_IP=y @@ -582,6 +588,7 @@ CONFIG_MSM_PERFORMANCE=y CONFIG_QMP_DEBUGFS_CLIENT=y CONFIG_QCOM_SMP2P_SLEEPSTATE=y CONFIG_QCOM_CDSP_RM=y +CONFIG_QCOM_AOP_DDR_MESSAGING=y CONFIG_DEVFREQ_GOV_PASSIVE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y @@ -600,7 +607,6 @@ CONFIG_PWM=y CONFIG_PWM_QTI_LPG=y CONFIG_QCOM_KGSL=y CONFIG_ARM_GIC_V3_ACL=y -CONFIG_ARM_DSU_PMU=y CONFIG_QCOM_LLCC_PMU=y CONFIG_RAS=y CONFIG_ANDROID=y diff --git a/arch/arm64/configs/vendor/sm8150_defconfig b/arch/arm64/configs/vendor/sm8150_defconfig index aa40d37015e844e2d5c36bca43d6753ad8ae8775..af95d573de5deccbfb64afd7947e27621de30744 100644 --- a/arch/arm64/configs/vendor/sm8150_defconfig +++ b/arch/arm64/configs/vendor/sm8150_defconfig @@ -64,6 +64,7 @@ CONFIG_ARCH_QCOM=y CONFIG_ARCH_SM8150=y CONFIG_PCI=y CONFIG_PCI_MSM=y +CONFIG_PCI_MSM_MSI=y CONFIG_SCHED_MC=y CONFIG_NR_CPUS=8 CONFIG_PREEMPT=y @@ -89,6 +90,7 @@ CONFIG_SETEND_EMULATION=y CONFIG_RANDOMIZE_BASE=y CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y +CONFIG_KRYO_PMU_WORKAROUND=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_COMPAT=y CONFIG_PM_AUTOSLEEP=y @@ -118,10 +120,12 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_SYN_COOKIES=y CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y +CONFIG_INET_UDP_DIAG=y CONFIG_INET_DIAG_DESTROY=y CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y @@ -183,6 +187,7 @@ CONFIG_NETFILTER_XT_MATCH_QTAGUID=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=y CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y @@ -218,6 +223,7 @@ CONFIG_IP6_NF_MANGLE=y CONFIG_IP6_NF_RAW=y CONFIG_BRIDGE_NF_EBTABLES=y CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_IP_SCTP=y CONFIG_L2TP=y CONFIG_L2TP_DEBUGFS=y CONFIG_L2TP_V3=y @@ -503,6 +509,7 @@ CONFIG_RTC_DRV_QPNP=y CONFIG_DMADEVICES=y CONFIG_QCOM_GPI_DMA=y CONFIG_QCOM_GPI_DMA_DEBUG=y +CONFIG_DEBUG_DMA_BUF_REF=y CONFIG_UIO=y CONFIG_UIO_MSM_SHAREDMEM=y CONFIG_STAGING=y @@ -608,6 +615,7 @@ CONFIG_MSM_PERFORMANCE=y CONFIG_QMP_DEBUGFS_CLIENT=y CONFIG_QCOM_SMP2P_SLEEPSTATE=y CONFIG_QCOM_CDSP_RM=y +CONFIG_QCOM_AOP_DDR_MESSAGING=y CONFIG_DEVFREQ_GOV_PASSIVE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y @@ -627,7 +635,6 @@ CONFIG_PWM_QTI_LPG=y CONFIG_QCOM_KGSL=y CONFIG_ARM_GIC_V3_ACL=y CONFIG_PHY_XGENE=y -CONFIG_ARM_DSU_PMU=y CONFIG_QCOM_LLCC_PMU=y CONFIG_RAS=y CONFIG_ANDROID=y diff --git a/arch/arm64/configs/vendor/trinket_defconfig b/arch/arm64/configs/vendor/trinket_defconfig new file mode 100644 index 0000000000000000000000000000000000000000..eb8e2c102896d373fdb67adca39cdbb89aecc70c --- /dev/null +++ b/arch/arm64/configs/vendor/trinket_defconfig @@ -0,0 +1,677 @@ +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_AUDIT=y +# CONFIG_AUDITSYSCALL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_SCHED_WALT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_BPF=y +CONFIG_CGROUP_DEBUG=y +CONFIG_SCHED_CORE_CTL=y +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_PID_NS is not set +CONFIG_SCHED_AUTOGROUP=y +CONFIG_SCHED_TUNE=y +CONFIG_DEFAULT_USE_ENERGY_AWARE=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_KALLSYMS_ALL=y +CONFIG_BPF_SYSCALL=y +# CONFIG_MEMBARRIER is not set +CONFIG_EMBEDDED=y +# CONFIG_COMPAT_BRK is not set +CONFIG_SLAB_FREELIST_RANDOM=y +CONFIG_SLAB_FREELIST_HARDENED=y +CONFIG_PROFILING=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_IOSCHED_DEADLINE is not set +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_TRINKET=y +CONFIG_PCI=y +CONFIG_PCI_MSM=y +CONFIG_SCHED_MC=y +CONFIG_NR_CPUS=8 +CONFIG_PREEMPT=y +CONFIG_HZ_100=y +CONFIG_CLEANCACHE=y +CONFIG_CMA=y +CONFIG_CMA_DEBUGFS=y +CONFIG_ZSMALLOC=y +CONFIG_SECCOMP=y +# CONFIG_UNMAP_KERNEL_AT_EL0 is not set +# CONFIG_HARDEN_BRANCH_PREDICTOR is not set +CONFIG_ARMV8_DEPRECATED=y +CONFIG_SWP_EMULATION=y +CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_SETEND_EMULATION=y +# CONFIG_ARM64_VHE is not set +CONFIG_RANDOMIZE_BASE=y +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_COMPAT=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_DEBUG=y +CONFIG_CPU_IDLE=y +CONFIG_ARM_CPUIDLE=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPVTI=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_BPF=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_SOCKET_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_NF_SOCKET_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_L2TP=y +CONFIG_L2TP_DEBUGFS=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y +CONFIG_DNS_RESOLVER=y +CONFIG_QRTR=y +CONFIG_QRTR_SMD=y +CONFIG_SOCKEV_NLMCAST=y +CONFIG_BT=y +CONFIG_MSM_BT_POWER=y +CONFIG_CFG80211=y +CONFIG_CFG80211_CERTIFICATION_ONUS=y +CONFIG_CFG80211_REG_CELLULAR_HINTS=y +CONFIG_CFG80211_INTERNAL_REGDB=y +# CONFIG_CFG80211_CRDA_SUPPORT is not set +CONFIG_RFKILL=y +CONFIG_NFC_NQ=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_REGMAP_WCD_IRQ=y +CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y +CONFIG_DMA_CMA=y +CONFIG_ZRAM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_QSEECOM=y +CONFIG_UID_SYS_STATS=y +CONFIG_MEMORY_STATE_TIME=y +CONFIG_QPNP_MISC=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFSHCD_CMD_LOGGING=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_NETDEVICES=y +CONFIG_BONDING=y +CONFIG_DUMMY=y +CONFIG_TUN=y +CONFIG_RMNET=y +CONFIG_PHYLIB=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_WIL6210=m +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_CLD_LL_CORE=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y +CONFIG_TOUCHSCREEN_HIMAX_I2C=y +CONFIG_TOUCHSCREEN_HIMAX_INCELL=y +CONFIG_TOUCHSCREEN_HIMAX_IC_HX83112=y +CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_TEST_REPORTING=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_UINPUT=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_MSM_GENI=y +CONFIG_SERIAL_MSM_GENI_CONSOLE=y +CONFIG_SERIAL_DEV_BUS=y +CONFIG_TTY_PRINTK=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +CONFIG_DIAG_CHAR=y +CONFIG_MSM_ADSPRPC=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_QCOM_GENI=y +CONFIG_SPI=y +CONFIG_SPI_QCOM_GENI=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPMI=y +CONFIG_SPMI_SIMULATOR=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_PINCTRL_TRINKET=y +CONFIG_GPIO_SYSFS=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y +CONFIG_POWER_RESET_XGENE=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_QPNP_QG=y +CONFIG_SMB1355_SLAVE_CHARGER=y +CONFIG_QPNP_SMB5=y +CONFIG_SMB1390_CHARGE_PUMP=y +CONFIG_THERMAL=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_QCOM_SPMI_TEMP_ALARM=y +CONFIG_THERMAL_TSENS=y +CONFIG_QTI_THERMAL_LIMITS_DCVS=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_AOP_REG_COOLING_DEVICE=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y +CONFIG_QTI_BCL_PMIC5=y +CONFIG_QTI_BCL_SOC_DRIVER=y +CONFIG_QTI_ADC_TM=y +CONFIG_MFD_I2C_PMIC=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_QPNP_LCDB=y +CONFIG_REGULATOR_REFGEN=y +CONFIG_REGULATOR_STUB=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_ADV_DEBUG=y +CONFIG_VIDEO_FIXED_MINOR_RANGES=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_SPECTRA_CAMERA=y +CONFIG_MSM_VIDC_V4L2=y +CONFIG_MSM_VIDC_GOVERNORS=y +CONFIG_MSM_SDE_ROTATOR=y +CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y +CONFIG_DRM=y +CONFIG_DRM_MSM_REGISTER_LOGGING=y +CONFIG_DRM_SDE_EVTLOG_DEBUG=y +CONFIG_DRM_SDE_RSC=y +CONFIG_FB_VIRTUAL=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_QCOM_SPMI_WLED=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_USB_AUDIO_QMI=y +CONFIG_SND_SOC=y +CONFIG_UHID=y +CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_PLANTRONICS=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_ISP1760=y +CONFIG_USB_ISP1760_HOST_ROLE=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_LINK_LAYER_TEST=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_USB_QCOM_EMU_PHY=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_MSM_QUSB_PHY=y +CONFIG_MSM_HSUSB_PHY=y +CONFIG_DUAL_ROLE_USB_INTF=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VBUS_DRAW=900 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_MTP=y +CONFIG_USB_CONFIGFS_F_PTP=y +CONFIG_USB_CONFIGFS_F_ACC=y +CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_MIDI=y +CONFIG_USB_CONFIGFS_F_HID=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_USB_CONFIGFS_F_CDEV=y +CONFIG_USB_CONFIGFS_F_CCID=y +CONFIG_USB_CONFIGFS_F_GSI=y +CONFIG_USB_CONFIGFS_F_QDSS=y +CONFIG_USB_PD_POLICY=y +CONFIG_QPNP_USB_PDPHY=y +CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_TEST=y +CONFIG_MMC_RING_BUFFER=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_CQ_HCI=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_QPNP_FLASH_V2=y +CONFIG_LEDS_QPNP_HAPTICS=y +CONFIG_LEDS_QTI_TRI_LED=y +CONFIG_LEDS_QPNP_VIBRATOR_LDO=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_EDAC=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_DMADEVICES=y +CONFIG_QCOM_GPI_DMA=y +CONFIG_QCOM_GPI_DMA_DEBUG=y +CONFIG_UIO=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ION=y +CONFIG_QCOM_GENI_SE=y +CONFIG_QPNP_REVID=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_USB_BAM=y +CONFIG_IPA3=y +CONFIG_IPA_WDI_UNIFIED_API=y +CONFIG_RMNET_IPA3=y +CONFIG_RNDIS_IPA=y +CONFIG_IPA_UT=y +CONFIG_MSM_11AD=m +CONFIG_SPMI_PMIC_CLKDIV=y +CONFIG_CLOCK_CPU_OSM=y +CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y +CONFIG_MAILBOX=y +CONFIG_QCOM_APCS_IPC=y +CONFIG_MSM_QMP=y +CONFIG_IOMMU_IO_PGTABLE_FAST=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_LAZY_MAPPING=y +CONFIG_IOMMU_DEBUG=y +CONFIG_IOMMU_DEBUG_TRACKING=y +CONFIG_IOMMU_TESTS=y +CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_QCOM_GLINK_RPM=y +CONFIG_RPMSG_QCOM_GLINK_SMEM=y +CONFIG_RPMSG_QCOM_GLINK_SPI=y +CONFIG_QCOM_CPUSS_DUMP=y +CONFIG_QCOM_RUN_QUEUE_STATS=y +CONFIG_QCOM_QMI_HELPERS=y +CONFIG_QCOM_SMEM=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_QCOM_WDOG_IPI_ENABLE=y +CONFIG_QCOM_SMP2P=y +CONFIG_QPNP_PBS=y +CONFIG_MSM_SERVICE_LOCATOR=y +CONFIG_MSM_SERVICE_NOTIFIER=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_SYSMON_QMI_COMM=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_SETUP_SSR_NOTIF_TIMEOUTS=y +CONFIG_PANIC_ON_SSR_NOTIF_TIMEOUT=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_MSM_CORE_HANG_DETECT=y +CONFIG_QCOM_DCC_V2=y +CONFIG_MSM_GLADIATOR_HANG_DETECT=y +CONFIG_QCOM_SECURE_BUFFER=y +CONFIG_ICNSS=y +CONFIG_ICNSS_DEBUG=y +CONFIG_ICNSS_QMI=y +CONFIG_QCOM_EUD=y +CONFIG_QCOM_MINIDUMP=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_QCOM_COMMAND_DB=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_QSEE_IPC_IRQ=y +CONFIG_QCOM_GLINK=y +CONFIG_QCOM_GLINK_PKT=y +CONFIG_QTI_RPM_STATS_LOG=y +CONFIG_MSM_CDSP_LOADER=y +CONFIG_QCOM_SMCINVOKE=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_PM=y +CONFIG_QCOM_FSA4480_I2C=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_QMP_DEBUGFS_CLIENT=y +CONFIG_QCOM_SMP2P_SLEEPSTATE=y +CONFIG_DEVFREQ_GOV_PASSIVE=y +CONFIG_QCOM_BIMC_BWMON=y +CONFIG_ARM_MEMLAT_MON=y +CONFIG_QCOMCCI_HWMON=y +CONFIG_QCOM_M4M_HWMON=y +CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_DEVFREQ_GOV_QCOM_CACHE_HWMON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y +CONFIG_DEVFREQ_SIMPLE_DEV=y +CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_EXTCON_USB_GPIO=y +CONFIG_IIO=y +CONFIG_QCOM_SPMI_ADC5=y +CONFIG_PWM=y +CONFIG_PWM_QTI_LPG=y +CONFIG_QCOM_KGSL=y +CONFIG_ARM_GIC_V3_ACL=y +CONFIG_PHY_XGENE=y +CONFIG_ARM_DSU_PMU=y +CONFIG_QCOM_LLCC_PMU=y +CONFIG_RAS=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_NVMEM_SPMI_SDAM=y +CONFIG_SENSORS_SSC=y +CONFIG_MSM_TZ_LOG=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_F2FS_FS=y +CONFIG_F2FS_FS_SECURITY=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_EFIVAR_FS=y +CONFIG_ECRYPT_FS=y +CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_SDCARD_FS=y +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_DEBUG_INFO=y +CONFIG_PAGE_OWNER=y +CONFIG_PAGE_OWNER_ENABLE_DEFAULT=y +CONFIG_DEBUG_SECTION_MISMATCH=y +# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_PAGEALLOC=y +CONFIG_SLUB_DEBUG_PANIC_ON=y +CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y +CONFIG_PAGE_POISONING=y +CONFIG_DEBUG_OBJECTS=y +CONFIG_DEBUG_OBJECTS_FREE=y +CONFIG_DEBUG_OBJECTS_TIMERS=y +CONFIG_DEBUG_OBJECTS_WORK=y +CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y +CONFIG_SLUB_DEBUG_ON=y +CONFIG_DEBUG_KMEMLEAK=y +CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000 +CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y +CONFIG_DEBUG_STACK_USAGE=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_SOFTLOCKUP_DETECTOR=y +CONFIG_WQ_WATCHDOG=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANIC_ON_SCHED_BUG=y +CONFIG_PANIC_ON_RT_THROTTLING=y +CONFIG_SCHEDSTATS=y +CONFIG_SCHED_STACK_END_CHECK=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_ATOMIC_SLEEP=y +CONFIG_LOCK_TORTURE_TEST=m +CONFIG_DEBUG_SG=y +CONFIG_DEBUG_NOTIFIERS=y +CONFIG_DEBUG_CREDENTIALS=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_FAULT_INJECTION=y +CONFIG_FAIL_PAGE_ALLOC=y +CONFIG_UFS_FAULT_INJECTION=y +CONFIG_FAULT_INJECTION_DEBUG_FS=y +CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y +CONFIG_IPC_LOGGING=y +CONFIG_QCOM_RTB=y +CONFIG_QCOM_RTB_SEPARATE_CPUS=y +CONFIG_FUNCTION_TRACER=y +CONFIG_IRQSOFF_TRACER=y +CONFIG_PREEMPT_TRACER=y +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_LKDTM=m +CONFIG_ATOMIC64_SELFTEST=m +CONFIG_TEST_USER_COPY=m +CONFIG_MEMTEST=y +CONFIG_BUG_ON_DATA_CORRUPTION=y +CONFIG_PID_IN_CONTEXTIDR=y +CONFIG_ARM64_STRICT_BREAK_BEFORE_MAKE=y +CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y +CONFIG_CORESIGHT_SOURCE_ETM4X=y +CONFIG_CORESIGHT_DYNAMIC_REPLICATOR=y +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_TPDA=y +CONFIG_CORESIGHT_TPDM=y +CONFIG_CORESIGHT_HWEVENT=y +CONFIG_CORESIGHT_DUMMY=y +CONFIG_CORESIGHT_REMOTE_ETM=y +CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 +CONFIG_CORESIGHT_TGU=y +CONFIG_CORESIGHT_EVENT=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_HARDENED_USERCOPY_PAGESPAN=y +CONFIG_FORTIFY_SOURCE=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_ARM64_CRYPTO=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_XZ_DEC=y diff --git a/arch/arm64/include/asm/cache.h b/arch/arm64/include/asm/cache.h index ea9bb4e0e9bbd002e8dec644bcb03dbb25f55f72..e40f8a2df5457d63cbd81694b0545ea6bfb823cf 100644 --- a/arch/arm64/include/asm/cache.h +++ b/arch/arm64/include/asm/cache.h @@ -20,9 +20,14 @@ #define CTR_L1IP_SHIFT 14 #define CTR_L1IP_MASK 3 +#define CTR_DMINLINE_SHIFT 16 +#define CTR_IMINLINE_SHIFT 0 #define CTR_CWG_SHIFT 24 #define CTR_CWG_MASK 15 +#define CTR_CACHE_MINLINE_MASK \ + (0xf << CTR_DMINLINE_SHIFT | 0xf << CTR_IMINLINE_SHIFT) + #define CTR_L1IP(ctr) (((ctr) >> CTR_L1IP_SHIFT) & CTR_L1IP_MASK) #define ICACHE_POLICY_VPIPT 0 diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h index ac16e2efb348226ec6ff4053de868e9325c81d1e..ab1149efda437496dc2f62ca8fe9fd73e3f00407 100644 --- a/arch/arm64/include/asm/cpucaps.h +++ b/arch/arm64/include/asm/cpucaps.h @@ -45,7 +45,8 @@ #define ARM64_HARDEN_BP_POST_GUEST_EXIT 25 #define ARM64_HW_DBM 26 #define ARM64_SSBD 27 +#define ARM64_MISMATCHED_CACHE_TYPE 28 -#define ARM64_NCAPS 28 +#define ARM64_NCAPS 29 #endif /* __ASM_CPUCAPS_H */ diff --git a/arch/arm64/include/asm/jump_label.h b/arch/arm64/include/asm/jump_label.h index 1b5e0e843c3af8e8035c8f48ef518a3505adb881..7e2b3e360086311427a0bc77ec609b77b43b740d 100644 --- a/arch/arm64/include/asm/jump_label.h +++ b/arch/arm64/include/asm/jump_label.h @@ -28,7 +28,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool branch) { - asm goto("1: nop\n\t" + asm_volatile_goto("1: nop\n\t" ".pushsection __jump_table, \"aw\"\n\t" ".align 3\n\t" ".quad 1b, %l[l_yes], %c0\n\t" @@ -42,7 +42,7 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch) { - asm goto("1: b %l[l_yes]\n\t" + asm_volatile_goto("1: b %l[l_yes]\n\t" ".pushsection __jump_table, \"aw\"\n\t" ".align 3\n\t" ".quad 1b, %l[l_yes], %c0\n\t" diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index e5df3fce00082a3aa6d1711188e6d1055012dc9d..2b55aee7c051844b7ac705f75b85c62301748697 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -42,6 +42,11 @@ void kvm_inject_vabt(struct kvm_vcpu *vcpu); void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr); void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr); +static inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu) +{ + return !(vcpu->arch.hcr_el2 & HCR_RW); +} + static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu) { vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS; diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 57dde8be92a4bf294bf918877a6e7a6889e97ba9..145ab666f64df8e663ce1f9d8636d5cb52764215 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -17,8 +17,8 @@ */ #include -#include #include +#include #include #include #include @@ -47,12 +47,18 @@ is_kryo_midr(const struct arm64_cpu_capabilities *entry, int scope) } static bool -has_mismatched_cache_line_size(const struct arm64_cpu_capabilities *entry, - int scope) +has_mismatched_cache_type(const struct arm64_cpu_capabilities *entry, + int scope) { + u64 mask = CTR_CACHE_MINLINE_MASK; + + /* Skip matching the min line sizes for cache type check */ + if (entry->capability == ARM64_MISMATCHED_CACHE_TYPE) + mask ^= arm64_ftr_reg_ctrel0.strict_mask; + WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible()); - return (read_cpuid_cachetype() & arm64_ftr_reg_ctrel0.strict_mask) != - (arm64_ftr_reg_ctrel0.sys_val & arm64_ftr_reg_ctrel0.strict_mask); + return (read_cpuid_cachetype() & mask) != + (arm64_ftr_reg_ctrel0.sys_val & mask); } static int cpu_enable_trap_ctr_access(void *__unused) @@ -475,7 +481,14 @@ const struct arm64_cpu_capabilities arm64_errata[] = { { .desc = "Mismatched cache line size", .capability = ARM64_MISMATCHED_CACHE_LINE_SIZE, - .matches = has_mismatched_cache_line_size, + .matches = has_mismatched_cache_type, + .def_scope = SCOPE_LOCAL_CPU, + .enable = cpu_enable_trap_ctr_access, + }, + { + .desc = "Mismatched cache type", + .capability = ARM64_MISMATCHED_CACHE_TYPE, + .matches = has_mismatched_cache_type, .def_scope = SCOPE_LOCAL_CPU, .enable = cpu_enable_trap_ctr_access, }, diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 5e621db943c9326931f6b6a9be0cf75c46ce0b3d..85c5208034c179d915c2732b4e87cf0497cb9ba9 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -180,14 +180,14 @@ static const struct arm64_ftr_bits ftr_ctr[] = { ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, 28, 1, 1), /* IDC */ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_HIGHER_SAFE, 24, 4, 0), /* CWG */ ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_HIGHER_SAFE, 20, 4, 0), /* ERG */ - ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, 16, 4, 1), /* DminLine */ + 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 * make use of *minLine. * If we have differing I-cache policies, report it as the weakest - VIPT. */ ARM64_FTR_BITS(FTR_VISIBLE, FTR_NONSTRICT, FTR_EXACT, 14, 2, ICACHE_POLICY_VIPT), /* L1Ip */ - ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, 0, 4, 0), /* IminLine */ + ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, CTR_IMINLINE_SHIFT, 4, 0), ARM64_FTR_END, }; diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index b6aeee12a33c46e0152cf917403e7898d878bf8b..4719ebb7faf9784a5731791d29d027d211a42f59 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -748,8 +748,8 @@ static irqreturn_t armv8pmu_handle_irq(int irq_num, void *dev) struct perf_event *event = cpuc->events[idx]; struct hw_perf_event *hwc; - /* Ignore if we don't have an event or if it's a zombie event */ - if (!event || event->state == PERF_EVENT_STATE_ZOMBIE) + /* Ignore if we don't have an event */ + if (!event || event->state != PERF_EVENT_STATE_ACTIVE) continue; /* diff --git a/arch/arm64/kernel/probes/kprobes.c b/arch/arm64/kernel/probes/kprobes.c index d849d9804011df6eabb143ed68da8d260dd5074d..22a5921562c7f84b9e6d25b8e3479269720780fe 100644 --- a/arch/arm64/kernel/probes/kprobes.c +++ b/arch/arm64/kernel/probes/kprobes.c @@ -275,7 +275,7 @@ static int __kprobes reenter_kprobe(struct kprobe *p, break; case KPROBE_HIT_SS: case KPROBE_REENTER: - pr_warn("Unrecoverable kprobe detected at %p.\n", p->addr); + pr_warn("Unrecoverable kprobe detected.\n"); dump_kprobe(p); BUG(); break; diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index edaf346d13d5fe31f4ec1a10d5a9647e46d92274..34d915b6974be24747cefed9bbff8b6c04882444 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -274,19 +274,22 @@ static int ptrace_hbp_set_event(unsigned int note_type, switch (note_type) { case NT_ARM_HW_BREAK: - if (idx < ARM_MAX_BRP) { - tsk->thread.debug.hbp_break[idx] = bp; - err = 0; - } + if (idx >= ARM_MAX_BRP) + goto out; + idx = array_index_nospec(idx, ARM_MAX_BRP); + tsk->thread.debug.hbp_break[idx] = bp; + err = 0; break; case NT_ARM_HW_WATCH: - if (idx < ARM_MAX_WRP) { - tsk->thread.debug.hbp_watch[idx] = bp; - err = 0; - } + if (idx >= ARM_MAX_WRP) + goto out; + idx = array_index_nospec(idx, ARM_MAX_WRP); + tsk->thread.debug.hbp_watch[idx] = bp; + err = 0; break; } +out: return err; } diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 043f562dde165e2436686270c971a27d57f1d9de..f7a5b92bfceeadcb3010ba77a20a4e9aefea6f84 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -218,7 +218,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle) * This is the secondary CPU boot entry. We're using this CPUs * idle thread stack, but a set of temporary page tables. */ -asmlinkage void secondary_start_kernel(void) +asmlinkage notrace void secondary_start_kernel(void) { struct mm_struct *mm = &init_mm; unsigned int cpu; diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 811f04c5760e40c5fd36adc6cb931921cbfa850a..76d27edf33cbffe4b30f72104554b5f1d32b8332 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -57,6 +57,45 @@ static u64 core_reg_offset_from_id(u64 id) return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE); } +static int validate_core_offset(const struct kvm_one_reg *reg) +{ + u64 off = core_reg_offset_from_id(reg->id); + int size; + + switch (off) { + case KVM_REG_ARM_CORE_REG(regs.regs[0]) ... + KVM_REG_ARM_CORE_REG(regs.regs[30]): + case KVM_REG_ARM_CORE_REG(regs.sp): + case KVM_REG_ARM_CORE_REG(regs.pc): + case KVM_REG_ARM_CORE_REG(regs.pstate): + case KVM_REG_ARM_CORE_REG(sp_el1): + case KVM_REG_ARM_CORE_REG(elr_el1): + case KVM_REG_ARM_CORE_REG(spsr[0]) ... + KVM_REG_ARM_CORE_REG(spsr[KVM_NR_SPSR - 1]): + size = sizeof(__u64); + break; + + case KVM_REG_ARM_CORE_REG(fp_regs.vregs[0]) ... + KVM_REG_ARM_CORE_REG(fp_regs.vregs[31]): + size = sizeof(__uint128_t); + break; + + case KVM_REG_ARM_CORE_REG(fp_regs.fpsr): + case KVM_REG_ARM_CORE_REG(fp_regs.fpcr): + size = sizeof(__u32); + break; + + default: + return -EINVAL; + } + + if (KVM_REG_SIZE(reg->id) == size && + IS_ALIGNED(off, size / sizeof(__u32))) + return 0; + + return -EINVAL; +} + static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) { /* @@ -76,6 +115,9 @@ static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs) return -ENOENT; + if (validate_core_offset(reg)) + return -EINVAL; + if (copy_to_user(uaddr, ((u32 *)regs) + off, KVM_REG_SIZE(reg->id))) return -EFAULT; @@ -98,6 +140,9 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs) return -ENOENT; + if (validate_core_offset(reg)) + return -EINVAL; + if (KVM_REG_SIZE(reg->id) > sizeof(tmp)) return -EINVAL; @@ -107,17 +152,25 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) } if (off == KVM_REG_ARM_CORE_REG(regs.pstate)) { - u32 mode = (*(u32 *)valp) & COMPAT_PSR_MODE_MASK; + u64 mode = (*(u64 *)valp) & COMPAT_PSR_MODE_MASK; switch (mode) { case COMPAT_PSR_MODE_USR: + if (!system_supports_32bit_el0()) + return -EINVAL; + break; case COMPAT_PSR_MODE_FIQ: case COMPAT_PSR_MODE_IRQ: case COMPAT_PSR_MODE_SVC: case COMPAT_PSR_MODE_ABT: case COMPAT_PSR_MODE_UND: + if (!vcpu_el1_is_32bit(vcpu)) + return -EINVAL; + break; case PSR_MODE_EL0t: case PSR_MODE_EL1t: case PSR_MODE_EL1h: + if (vcpu_el1_is_32bit(vcpu)) + return -EINVAL; break; default: err = -EINVAL; diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index 0595236e2fa4dcc020d2e23eaa78482f919bdb5e..39d00f15bd46881e05eb54524f38805f9f771866 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c @@ -770,13 +770,14 @@ static void *__iommu_alloc_attrs(struct device *dev, size_t size, size >> PAGE_SHIFT); return NULL; } - if (!coherent) - __dma_flush_area(page_to_virt(page), iosize); - addr = dma_common_contiguous_remap(page, size, VM_USERMAP, prot, __builtin_return_address(0)); - if (!addr) { + if (addr) { + memset(addr, 0, size); + if (!coherent) + __dma_flush_area(page_to_virt(page), iosize); + } else { iommu_dma_unmap_page(dev, *handle, iosize, 0, attrs); dma_release_from_contiguous(dev, page, size >> PAGE_SHIFT); diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 9e493cab40a963e3de7ed913a23fc95810a0babe..573105191e44c89a6e826a225a6524be563ad400 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -125,6 +125,7 @@ static void mem_abort_decode(unsigned int esr) pr_alert(" EA = %lu, S1PTW = %lu\n", (esr & ESR_ELx_EA) >> ESR_ELx_EA_SHIFT, (esr & ESR_ELx_S1PTW) >> ESR_ELx_S1PTW_SHIFT); + pr_alert(" FSC = %lu\n", (esr & ESR_ELx_FSC)); if (esr_is_data_abort(esr)) data_abort_decode(esr); diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index cc1b7acea13e1527476267c12fd32cce3c8dd213..b89eec1ad6b37f3b848cfac09cd7c200faf228a4 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -288,11 +288,13 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max) #endif /* CONFIG_NUMA */ #ifdef CONFIG_HAVE_ARCH_PFN_VALID -#define PFN_MASK ((1UL << (64 - PAGE_SHIFT)) - 1) - int pfn_valid(unsigned long pfn) { - return (pfn & PFN_MASK) == pfn && memblock_is_map_memory(pfn << PAGE_SHIFT); + phys_addr_t addr = pfn << PAGE_SHIFT; + + if ((addr >> PAGE_SHIFT) != pfn) + return 0; + return memblock_is_map_memory(addr); } EXPORT_SYMBOL(pfn_valid); #endif diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 6b56c0b6f8d86255ba0b0a2317ecc8236e32ea3e..f749e1d50cf15e6b7f49506265b77653f0d7a60a 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -1380,12 +1380,12 @@ int pmd_clear_huge(pmd_t *pmd) return 1; } -int pud_free_pmd_page(pud_t *pud) +int pud_free_pmd_page(pud_t *pud, unsigned long addr) { return pud_none(*pud); } -int pmd_free_pte_page(pmd_t *pmd) +int pmd_free_pte_page(pmd_t *pmd, unsigned long addr) { return pmd_none(*pmd); } diff --git a/arch/hexagon/include/asm/bitops.h b/arch/hexagon/include/asm/bitops.h index 5e4a59b3ec1bb042f25de860a8489340a7add291..2691a1857d203db2522ae178fe744225c71d2da9 100644 --- a/arch/hexagon/include/asm/bitops.h +++ b/arch/hexagon/include/asm/bitops.h @@ -211,7 +211,7 @@ static inline long ffz(int x) * This is defined the same way as ffs. * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. */ -static inline long fls(int x) +static inline int fls(int x) { int r; @@ -232,7 +232,7 @@ static inline long fls(int x) * the libc and compiler builtin ffs routines, therefore * differs in spirit from the above ffz (man ffs). */ -static inline long ffs(int x) +static inline int ffs(int x) { int r; diff --git a/arch/hexagon/kernel/dma.c b/arch/hexagon/kernel/dma.c index 546792d176a4801b7b4f7659ec3953a948a85ba0..564651bded425d607e0143fa0117e3272c7a494a 100644 --- a/arch/hexagon/kernel/dma.c +++ b/arch/hexagon/kernel/dma.c @@ -59,7 +59,7 @@ static void *hexagon_dma_alloc_coherent(struct device *dev, size_t size, panic("Can't create %s() memory pool!", __func__); else gen_pool_add(coherent_pool, - pfn_to_virt(max_low_pfn), + (unsigned long)pfn_to_virt(max_low_pfn), hexagon_coherent_pool_size, -1); } diff --git a/arch/m68k/include/asm/mcf_pgalloc.h b/arch/m68k/include/asm/mcf_pgalloc.h index 8b707c249026032ac8bef80c6f1666c105d9b50d..12fe700632f458ea632a18bb9cdccd6660efd241 100644 --- a/arch/m68k/include/asm/mcf_pgalloc.h +++ b/arch/m68k/include/asm/mcf_pgalloc.h @@ -44,6 +44,7 @@ extern inline pmd_t *pmd_alloc_kernel(pgd_t *pgd, unsigned long address) static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t page, unsigned long address) { + pgtable_page_dtor(page); __free_page(page); } @@ -74,8 +75,9 @@ static inline struct page *pte_alloc_one(struct mm_struct *mm, return page; } -extern inline void pte_free(struct mm_struct *mm, struct page *page) +static inline void pte_free(struct mm_struct *mm, struct page *page) { + pgtable_page_dtor(page); __free_page(page); } diff --git a/arch/mips/Makefile b/arch/mips/Makefile index a96d97a806c9906e826ae8a1086be7eb7a8ff65f..5977884b008e6d798755dbf98ae5d29fda1b015c 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -155,15 +155,11 @@ cflags-$(CONFIG_CPU_R4300) += -march=r4300 -Wa,--trap cflags-$(CONFIG_CPU_VR41XX) += -march=r4100 -Wa,--trap cflags-$(CONFIG_CPU_R4X00) += -march=r4600 -Wa,--trap cflags-$(CONFIG_CPU_TX49XX) += -march=r4600 -Wa,--trap -cflags-$(CONFIG_CPU_MIPS32_R1) += $(call cc-option,-march=mips32,-mips32 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \ - -Wa,-mips32 -Wa,--trap -cflags-$(CONFIG_CPU_MIPS32_R2) += $(call cc-option,-march=mips32r2,-mips32r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \ - -Wa,-mips32r2 -Wa,--trap +cflags-$(CONFIG_CPU_MIPS32_R1) += -march=mips32 -Wa,--trap +cflags-$(CONFIG_CPU_MIPS32_R2) += -march=mips32r2 -Wa,--trap cflags-$(CONFIG_CPU_MIPS32_R6) += -march=mips32r6 -Wa,--trap -modd-spreg -cflags-$(CONFIG_CPU_MIPS64_R1) += $(call cc-option,-march=mips64,-mips64 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS64) \ - -Wa,-mips64 -Wa,--trap -cflags-$(CONFIG_CPU_MIPS64_R2) += $(call cc-option,-march=mips64r2,-mips64r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS64) \ - -Wa,-mips64r2 -Wa,--trap +cflags-$(CONFIG_CPU_MIPS64_R1) += -march=mips64 -Wa,--trap +cflags-$(CONFIG_CPU_MIPS64_R2) += -march=mips64r2 -Wa,--trap cflags-$(CONFIG_CPU_MIPS64_R6) += -march=mips64r6 -Wa,--trap cflags-$(CONFIG_CPU_R5000) += -march=r5000 -Wa,--trap cflags-$(CONFIG_CPU_R5432) += $(call cc-option,-march=r5400,-march=r5000) \ diff --git a/arch/mips/ath79/setup.c b/arch/mips/ath79/setup.c index f206dafbb0a35f57ccd64bfbefd24bbe112ff4f7..26a058d58d37b2ae10ca634b8025d6a01d0b6346 100644 --- a/arch/mips/ath79/setup.c +++ b/arch/mips/ath79/setup.c @@ -40,6 +40,7 @@ static char ath79_sys_type[ATH79_SYS_TYPE_LEN]; static void ath79_restart(char *command) { + local_irq_disable(); ath79_device_reset_set(AR71XX_RESET_FULL_CHIP); for (;;) if (cpu_wait) diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index 8c9cbf13d32a0a471bc6f2653bbb3c459b1b2c2c..6054d49e608eec038e1bbd49599bc783270aa09a 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -212,12 +212,6 @@ static int __init bcm47xx_cpu_fixes(void) */ if (bcm47xx_bus.bcma.bus.chipinfo.id == BCMA_CHIP_ID_BCM4706) cpu_wait = NULL; - - /* - * BCM47XX Erratum "R10: PCIe Transactions Periodically Fail" - * Enable ExternalSync for sync instruction to take effect - */ - set_c0_config7(MIPS_CONF7_ES); break; #endif } diff --git a/arch/mips/boot/Makefile b/arch/mips/boot/Makefile index c22da16d67b82f7752f6ba39291e2acd4e18fb47..5c7bfa8478e7522a854c93f89e4990170e58eb3b 100644 --- a/arch/mips/boot/Makefile +++ b/arch/mips/boot/Makefile @@ -118,10 +118,12 @@ ifeq ($(ADDR_BITS),64) itb_addr_cells = 2 endif +targets += vmlinux.its.S + quiet_cmd_its_cat = CAT $@ - cmd_its_cat = cat $^ >$@ + cmd_its_cat = cat $(filter-out $(PHONY), $^) >$@ -$(obj)/vmlinux.its.S: $(addprefix $(srctree)/arch/mips/$(PLATFORM)/,$(ITS_INPUTS)) +$(obj)/vmlinux.its.S: $(addprefix $(srctree)/arch/mips/$(PLATFORM)/,$(ITS_INPUTS)) FORCE $(call if_changed,its_cat) quiet_cmd_cpp_its_S = ITS $@ diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c index 8505db478904b10855eabf266f75ff9dd93e3699..1d92efb82c3729173e01d64b660f961bc42dd9b8 100644 --- a/arch/mips/cavium-octeon/octeon-platform.c +++ b/arch/mips/cavium-octeon/octeon-platform.c @@ -322,6 +322,7 @@ static int __init octeon_ehci_device_init(void) return 0; pd = of_find_device_by_node(ehci_node); + of_node_put(ehci_node); if (!pd) return 0; @@ -384,6 +385,7 @@ static int __init octeon_ohci_device_init(void) return 0; pd = of_find_device_by_node(ohci_node); + of_node_put(ohci_node); if (!pd) return 0; diff --git a/arch/mips/generic/init.c b/arch/mips/generic/init.c index 5ba6fcc26fa726aff50cc3a64315855eb935c1b0..94a78dbbc91f78acb51a8f092ae084646f1c2182 100644 --- a/arch/mips/generic/init.c +++ b/arch/mips/generic/init.c @@ -204,6 +204,7 @@ void __init arch_init_irq(void) "mti,cpu-interrupt-controller"); if (!cpu_has_veic && !intc_node) mips_cpu_irq_init(); + of_node_put(intc_node); irqchip_init(); } diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index cea8ad864b3f6f416cb45687bfbcb5bd882933a7..57b34257be2bf03826bbf332b4461e834e1f791d 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -141,14 +141,14 @@ static inline void * phys_to_virt(unsigned long address) /* * ISA I/O bus memory addresses are 1:1 with the physical address. */ -static inline unsigned long isa_virt_to_bus(volatile void * address) +static inline unsigned long isa_virt_to_bus(volatile void *address) { - return (unsigned long)address - PAGE_OFFSET; + return virt_to_phys(address); } -static inline void * isa_bus_to_virt(unsigned long address) +static inline void *isa_bus_to_virt(unsigned long address) { - return (void *)(address + PAGE_OFFSET); + return phys_to_virt(address); } #define isa_page_to_bus page_to_phys diff --git a/arch/mips/include/asm/mach-ath79/ath79.h b/arch/mips/include/asm/mach-ath79/ath79.h index 441faa92c3cd488ac97685a1930597f7449a88f4..6e6c0fead776d22b94b444a7ff3c9af91daa9935 100644 --- a/arch/mips/include/asm/mach-ath79/ath79.h +++ b/arch/mips/include/asm/mach-ath79/ath79.h @@ -134,6 +134,7 @@ static inline u32 ath79_pll_rr(unsigned reg) static inline void ath79_reset_wr(unsigned reg, u32 val) { __raw_writel(val, ath79_reset_base + reg); + (void) __raw_readl(ath79_reset_base + reg); /* flush */ } static inline u32 ath79_reset_rr(unsigned reg) diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 60c787d943b059ed33561bb127e60ce07ef0198c..a6810923b3f0214dfa36eab4a28320a65bba7790 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -680,8 +680,6 @@ #define MIPS_CONF7_WII (_ULCAST_(1) << 31) #define MIPS_CONF7_RPS (_ULCAST_(1) << 2) -/* ExternalSync */ -#define MIPS_CONF7_ES (_ULCAST_(1) << 8) #define MIPS_CONF7_IAR (_ULCAST_(1) << 10) #define MIPS_CONF7_AR (_ULCAST_(1) << 16) @@ -2747,7 +2745,6 @@ __BUILD_SET_C0(status) __BUILD_SET_C0(cause) __BUILD_SET_C0(config) __BUILD_SET_C0(config5) -__BUILD_SET_C0(config7) __BUILD_SET_C0(intcontrol) __BUILD_SET_C0(intctl) __BUILD_SET_C0(srsmap) diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h index 95b8c471f572b07d8d313fbadc96d5f1b71a035a..eb1f6030ab853d9990a6e59695db438c48c8bc70 100644 --- a/arch/mips/include/asm/processor.h +++ b/arch/mips/include/asm/processor.h @@ -141,7 +141,7 @@ struct mips_fpu_struct { #define NUM_DSP_REGS 6 -typedef __u32 dspreg_t; +typedef unsigned long dspreg_t; struct mips_dsp_state { dspreg_t dspr[NUM_DSP_REGS]; @@ -388,7 +388,20 @@ unsigned long get_wchan(struct task_struct *p); #define KSTK_ESP(tsk) (task_pt_regs(tsk)->regs[29]) #define KSTK_STATUS(tsk) (task_pt_regs(tsk)->cp0_status) +#ifdef CONFIG_CPU_LOONGSON3 +/* + * Loongson-3's SFB (Store-Fill-Buffer) may buffer writes indefinitely when a + * tight read loop is executed, because reads take priority over writes & the + * hardware (incorrectly) doesn't ensure that writes will eventually occur. + * + * Since spin loops of any kind should have a cpu_relax() in them, force an SFB + * flush from cpu_relax() such that any pending writes will become visible as + * expected. + */ +#define cpu_relax() smp_mb() +#else #define cpu_relax() barrier() +#endif /* * Return_address is a replacement for __builtin_return_address(count) diff --git a/arch/mips/jz4740/Platform b/arch/mips/jz4740/Platform index 28448d358c10d42c6ed5600ed3a5e5d67919e7e5..a2a5a85ea1f9360d3ff90e7e0419c423b6a0fbdf 100644 --- a/arch/mips/jz4740/Platform +++ b/arch/mips/jz4740/Platform @@ -1,4 +1,4 @@ platform-$(CONFIG_MACH_INGENIC) += jz4740/ cflags-$(CONFIG_MACH_INGENIC) += -I$(srctree)/arch/mips/include/asm/mach-jz4740 load-$(CONFIG_MACH_INGENIC) += 0xffffffff80010000 -zload-$(CONFIG_MACH_INGENIC) += 0xffffffff80600000 +zload-$(CONFIG_MACH_INGENIC) += 0xffffffff81000000 diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index e058cd300713d19bf656bc243f3f6cec9728a962..efffdf2464ab76d85b7b5e35d089323c70f0164f 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -847,7 +847,7 @@ long arch_ptrace(struct task_struct *child, long request, goto out; } dregs = __get_dsp_regs(child); - tmp = (unsigned long) (dregs[addr - DSP_BASE]); + tmp = dregs[addr - DSP_BASE]; break; } case DSP_CONTROL: diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index 89026d33a07bf7027400e56fa49fcb65da21ea60..6990240785f6c0cd8dbcfeaed237502739f82fe8 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c @@ -141,7 +141,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, goto out; } dregs = __get_dsp_regs(child); - tmp = (unsigned long) (dregs[addr - DSP_BASE]); + tmp = dregs[addr - DSP_BASE]; break; } case DSP_CONTROL: diff --git a/arch/mips/kernel/vdso.c b/arch/mips/kernel/vdso.c index 019035d7225c4fd942c96c6628b6605f8d2af1b4..8f845f6e5f4266568288969b9b19b7357b86598b 100644 --- a/arch/mips/kernel/vdso.c +++ b/arch/mips/kernel/vdso.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -20,6 +21,7 @@ #include #include +#include #include /* Kernel-provided data used by the VDSO. */ @@ -128,12 +130,30 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) vvar_size = gic_size + PAGE_SIZE; size = vvar_size + image->size; + /* + * Find a region that's large enough for us to perform the + * colour-matching alignment below. + */ + if (cpu_has_dc_aliases) + size += shm_align_mask + 1; + base = get_unmapped_area(NULL, 0, size, 0, 0); if (IS_ERR_VALUE(base)) { ret = base; goto out; } + /* + * If we suffer from dcache aliasing, ensure that the VDSO data page + * mapping is coloured the same as the kernel's mapping of that memory. + * This ensures that when the kernel updates the VDSO data userland + * will observe it without requiring cache invalidations. + */ + if (cpu_has_dc_aliases) { + base = __ALIGN_MASK(base, shm_align_mask); + base += ((unsigned long)&vdso_data - gic_size) & shm_align_mask; + } + data_addr = base + gic_size; vdso_addr = data_addr + PAGE_SIZE; diff --git a/arch/mips/lib/multi3.c b/arch/mips/lib/multi3.c index 111ad475aa0cdd111ebe362af928414d9499f666..4c2483f410c26b5b65ded652c1b0694b06a9bf92 100644 --- a/arch/mips/lib/multi3.c +++ b/arch/mips/lib/multi3.c @@ -4,12 +4,12 @@ #include "libgcc.h" /* - * GCC 7 suboptimally generates __multi3 calls for mips64r6, so for that - * specific case only we'll implement it here. + * GCC 7 & older can suboptimally generate __multi3 calls for mips64r6, so for + * that specific case only we implement that intrinsic here. * * See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82981 */ -#if defined(CONFIG_64BIT) && defined(CONFIG_CPU_MIPSR6) && (__GNUC__ == 7) +#if defined(CONFIG_64BIT) && defined(CONFIG_CPU_MIPSR6) && (__GNUC__ < 8) /* multiply 64-bit values, low 64-bits returned */ static inline long long notrace dmulu(long long a, long long b) diff --git a/arch/mips/loongson64/common/cs5536/cs5536_ohci.c b/arch/mips/loongson64/common/cs5536/cs5536_ohci.c index f7c905e50dc415e21eb258b08a69cc61525bd67b..92dc6bafc1271795b3c66b7c21467f3c22214fd0 100644 --- a/arch/mips/loongson64/common/cs5536/cs5536_ohci.c +++ b/arch/mips/loongson64/common/cs5536/cs5536_ohci.c @@ -138,7 +138,7 @@ u32 pci_ohci_read_reg(int reg) break; case PCI_OHCI_INT_REG: _rdmsr(DIVIL_MSR_REG(PIC_YSEL_LOW), &hi, &lo); - if ((lo & 0x00000f00) == CS5536_USB_INTR) + if (((lo >> PIC_YSEL_LOW_USB_SHIFT) & 0xf) == CS5536_USB_INTR) conf_data = 1; break; default: diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index e12dfa48b478dd3ec51369236bb84040c044bd82..a5893b2cdc0e051bb55f69a021c3d4a742309d7b 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -835,7 +835,8 @@ static void r4k_flush_icache_user_range(unsigned long start, unsigned long end) static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) { /* Catch bad driver code */ - BUG_ON(size == 0); + if (WARN_ON(size == 0)) + return; preempt_disable(); if (cpu_has_inclusive_pcaches) { @@ -871,7 +872,8 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size) static void r4k_dma_cache_inv(unsigned long addr, unsigned long size) { /* Catch bad driver code */ - BUG_ON(size == 0); + if (WARN_ON(size == 0)) + return; preempt_disable(); if (cpu_has_inclusive_pcaches) { diff --git a/arch/openrisc/kernel/entry.S b/arch/openrisc/kernel/entry.S index 1b7160c79646be4e136d0f813b4b55c0bfd63827..b16e95a4e875fd742fbaf3ce9aaa3d63b2ba88ce 100644 --- a/arch/openrisc/kernel/entry.S +++ b/arch/openrisc/kernel/entry.S @@ -221,12 +221,6 @@ EXCEPTION_ENTRY(_data_page_fault_handler) l.addi r3,r1,0 // pt_regs /* r4 set be EXCEPTION_HANDLE */ // effective address of fault - /* - * __PHX__: TODO - * - * all this can be written much simpler. look at - * DTLB miss handler in the CONFIG_GUARD_PROTECTED_CORE part - */ #ifdef CONFIG_OPENRISC_NO_SPR_SR_DSX l.lwz r6,PT_PC(r3) // address of an offending insn l.lwz r6,0(r6) // instruction that caused pf @@ -258,7 +252,7 @@ EXCEPTION_ENTRY(_data_page_fault_handler) #else - l.lwz r6,PT_SR(r3) // SR + l.mfspr r6,r0,SPR_SR // SR l.andi r6,r6,SPR_SR_DSX // check for delay slot exception l.sfne r6,r0 // exception happened in delay slot l.bnf 7f diff --git a/arch/openrisc/kernel/head.S b/arch/openrisc/kernel/head.S index 1e87913576e304e47ea7da5518436d3e0fe3f94e..90979acdf165b4d8ed74e02b9b1a049ac1f6c720 100644 --- a/arch/openrisc/kernel/head.S +++ b/arch/openrisc/kernel/head.S @@ -141,8 +141,7 @@ * r4 - EEAR exception EA * r10 - current pointing to current_thread_info struct * r12 - syscall 0, since we didn't come from syscall - * r13 - temp it actually contains new SR, not needed anymore - * r31 - handler address of the handler we'll jump to + * r30 - handler address of the handler we'll jump to * * handler has to save remaining registers to the exception * ksp frame *before* tainting them! @@ -178,6 +177,7 @@ /* r1 is KSP, r30 is __pa(KSP) */ ;\ tophys (r30,r1) ;\ l.sw PT_GPR12(r30),r12 ;\ + /* r4 use for tmp before EA */ ;\ l.mfspr r12,r0,SPR_EPCR_BASE ;\ l.sw PT_PC(r30),r12 ;\ l.mfspr r12,r0,SPR_ESR_BASE ;\ @@ -197,7 +197,10 @@ /* r12 == 1 if we come from syscall */ ;\ CLEAR_GPR(r12) ;\ /* ----- turn on MMU ----- */ ;\ - l.ori r30,r0,(EXCEPTION_SR) ;\ + /* Carry DSX into exception SR */ ;\ + l.mfspr r30,r0,SPR_SR ;\ + l.andi r30,r30,SPR_SR_DSX ;\ + l.ori r30,r30,(EXCEPTION_SR) ;\ l.mtspr r0,r30,SPR_ESR_BASE ;\ /* r30: EA address of handler */ ;\ LOAD_SYMBOL_2_GPR(r30,handler) ;\ diff --git a/arch/openrisc/kernel/traps.c b/arch/openrisc/kernel/traps.c index 8d8437169b5e7496b589e71c686c06348035fdbd..0d44e8007ad6e16f7cfcac027dabb89903f99d87 100644 --- a/arch/openrisc/kernel/traps.c +++ b/arch/openrisc/kernel/traps.c @@ -358,7 +358,7 @@ static inline int in_delay_slot(struct pt_regs *regs) return 0; } #else - return regs->sr & SPR_SR_DSX; + return mfspr(SPR_SR) & SPR_SR_DSX; #endif } diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index 1fd3eb5b66c6c6586c028b9002dcb185f6d54e56..89e684fd795f1501a4dfc279b5f01d4919724079 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig @@ -201,7 +201,7 @@ config PREFETCH config MLONGCALLS bool "Enable the -mlong-calls compiler option for big kernels" - def_bool y if (!MODULES) + default y depends on PA8X00 help If you configure the kernel to include many drivers built-in instead diff --git a/arch/parisc/include/asm/barrier.h b/arch/parisc/include/asm/barrier.h new file mode 100644 index 0000000000000000000000000000000000000000..dbaaca84f27f342ef1c1b8c743e66fa4d6a6f8eb --- /dev/null +++ b/arch/parisc/include/asm/barrier.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_BARRIER_H +#define __ASM_BARRIER_H + +#ifndef __ASSEMBLY__ + +/* The synchronize caches instruction executes as a nop on systems in + which all memory references are performed in order. */ +#define synchronize_caches() __asm__ __volatile__ ("sync" : : : "memory") + +#if defined(CONFIG_SMP) +#define mb() do { synchronize_caches(); } while (0) +#define rmb() mb() +#define wmb() mb() +#define dma_rmb() mb() +#define dma_wmb() mb() +#else +#define mb() barrier() +#define rmb() barrier() +#define wmb() barrier() +#define dma_rmb() barrier() +#define dma_wmb() barrier() +#endif + +#define __smp_mb() mb() +#define __smp_rmb() mb() +#define __smp_wmb() mb() + +#include + +#endif /* !__ASSEMBLY__ */ +#endif /* __ASM_BARRIER_H */ diff --git a/arch/parisc/include/asm/spinlock.h b/arch/parisc/include/asm/spinlock.h index af03359e6ac5685d6fa93361b5a0f4f4817a8cae..a82776592c8e5e8a346dadb8f753e18082bcccaf 100644 --- a/arch/parisc/include/asm/spinlock.h +++ b/arch/parisc/include/asm/spinlock.h @@ -20,7 +20,6 @@ static inline void arch_spin_lock_flags(arch_spinlock_t *x, { volatile unsigned int *a; - mb(); a = __ldcw_align(x); while (__ldcw(a) == 0) while (*a == 0) @@ -30,16 +29,15 @@ static inline void arch_spin_lock_flags(arch_spinlock_t *x, local_irq_disable(); } else cpu_relax(); - mb(); } static inline void arch_spin_unlock(arch_spinlock_t *x) { volatile unsigned int *a; - mb(); + a = __ldcw_align(x); - *a = 1; mb(); + *a = 1; } static inline int arch_spin_trylock(arch_spinlock_t *x) @@ -47,10 +45,8 @@ static inline int arch_spin_trylock(arch_spinlock_t *x) volatile unsigned int *a; int ret; - mb(); a = __ldcw_align(x); ret = __ldcw(a) != 0; - mb(); return ret; } diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index e95207c0565eb12308e12d48c45bd5309ae6e2ae..1b4732e201374adc2721ab7141e5ed9b5bf9bd69 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -481,6 +481,8 @@ /* Release pa_tlb_lock lock without reloading lock address. */ .macro tlb_unlock0 spc,tmp #ifdef CONFIG_SMP + or,COND(=) %r0,\spc,%r0 + sync or,COND(=) %r0,\spc,%r0 stw \spc,0(\tmp) #endif diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S index 67b0f7532e835f4db1214c6ccecf62183eb84e50..3e163df49cf30210c441324ca7d0424ddf701e49 100644 --- a/arch/parisc/kernel/pacache.S +++ b/arch/parisc/kernel/pacache.S @@ -354,6 +354,7 @@ ENDPROC_CFI(flush_data_cache_local) .macro tlb_unlock la,flags,tmp #ifdef CONFIG_SMP ldi 1,\tmp + sync stw \tmp,0(\la) mtsm \flags #endif diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S index e775f80ae28c5ab8d7fac7456235fa4f415c7215..5f7e57fcaeef0333da7482f8af566a0e4da7fc00 100644 --- a/arch/parisc/kernel/syscall.S +++ b/arch/parisc/kernel/syscall.S @@ -629,11 +629,12 @@ cas_action: stw %r1, 4(%sr2,%r20) #endif /* The load and store could fail */ -1: ldw,ma 0(%r26), %r28 +1: ldw 0(%r26), %r28 sub,<> %r28, %r25, %r0 -2: stw,ma %r24, 0(%r26) +2: stw %r24, 0(%r26) /* Free lock */ - stw,ma %r20, 0(%sr2,%r20) + sync + stw %r20, 0(%sr2,%r20) #if ENABLE_LWS_DEBUG /* Clear thread register indicator */ stw %r0, 4(%sr2,%r20) @@ -647,6 +648,7 @@ cas_action: 3: /* Error occurred on load or store */ /* Free lock */ + sync stw %r20, 0(%sr2,%r20) #if ENABLE_LWS_DEBUG stw %r0, 4(%sr2,%r20) @@ -796,30 +798,30 @@ cas2_action: ldo 1(%r0),%r28 /* 8bit CAS */ -13: ldb,ma 0(%r26), %r29 +13: ldb 0(%r26), %r29 sub,= %r29, %r25, %r0 b,n cas2_end -14: stb,ma %r24, 0(%r26) +14: stb %r24, 0(%r26) b cas2_end copy %r0, %r28 nop nop /* 16bit CAS */ -15: ldh,ma 0(%r26), %r29 +15: ldh 0(%r26), %r29 sub,= %r29, %r25, %r0 b,n cas2_end -16: sth,ma %r24, 0(%r26) +16: sth %r24, 0(%r26) b cas2_end copy %r0, %r28 nop nop /* 32bit CAS */ -17: ldw,ma 0(%r26), %r29 +17: ldw 0(%r26), %r29 sub,= %r29, %r25, %r0 b,n cas2_end -18: stw,ma %r24, 0(%r26) +18: stw %r24, 0(%r26) b cas2_end copy %r0, %r28 nop @@ -827,10 +829,10 @@ cas2_action: /* 64bit CAS */ #ifdef CONFIG_64BIT -19: ldd,ma 0(%r26), %r29 +19: ldd 0(%r26), %r29 sub,*= %r29, %r25, %r0 b,n cas2_end -20: std,ma %r24, 0(%r26) +20: std %r24, 0(%r26) copy %r0, %r28 #else /* Compare first word */ @@ -848,7 +850,8 @@ cas2_action: cas2_end: /* Free lock */ - stw,ma %r20, 0(%sr2,%r20) + sync + stw %r20, 0(%sr2,%r20) /* Enable interrupts */ ssm PSW_SM_I, %r0 /* Return to userspace, set no error */ @@ -858,6 +861,7 @@ cas2_end: 22: /* Error occurred on load or store */ /* Free lock */ + sync stw %r20, 0(%sr2,%r20) ssm PSW_SM_I, %r0 ldo 1(%r0),%r28 diff --git a/arch/powerpc/include/asm/fadump.h b/arch/powerpc/include/asm/fadump.h index 5a23010af600337b89887cab179cf2e9b1b385b0..1e7a33592e297aae7f6e5001c20d3b005eb6d81c 100644 --- a/arch/powerpc/include/asm/fadump.h +++ b/arch/powerpc/include/asm/fadump.h @@ -195,9 +195,6 @@ struct fadump_crash_info_header { struct cpumask online_mask; }; -/* Crash memory ranges */ -#define INIT_CRASHMEM_RANGES (INIT_MEMBLOCK_REGIONS + 2) - struct fad_crash_memory_ranges { unsigned long long base; unsigned long long size; diff --git a/arch/powerpc/include/asm/setup.h b/arch/powerpc/include/asm/setup.h index bbcdf929be544264142e60f43e5b4a096db51bfc..a5e919e34c42198e9711c5ee069398ec1ca2cc6d 100644 --- a/arch/powerpc/include/asm/setup.h +++ b/arch/powerpc/include/asm/setup.h @@ -9,6 +9,7 @@ extern void ppc_printk_progress(char *s, unsigned short hex); extern unsigned int rtas_data; extern unsigned long long memory_limit; +extern bool init_mem_is_free; extern unsigned long klimit; extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask); diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h index 11f4bd07cce0ee0fde57d031634a3b6d2a3b1dda..565cead12be2fb3be3535a44d224a8ff9facc9b3 100644 --- a/arch/powerpc/include/asm/uaccess.h +++ b/arch/powerpc/include/asm/uaccess.h @@ -223,10 +223,17 @@ do { \ } \ } while (0) +/* + * This is a type: either unsigned long, if the argument fits into + * that type, or otherwise unsigned long long. + */ +#define __long_type(x) \ + __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL)) + #define __get_user_nocheck(x, ptr, size) \ ({ \ long __gu_err; \ - unsigned long __gu_val; \ + __long_type(*(ptr)) __gu_val; \ const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ __chk_user_ptr(ptr); \ if (!is_kernel_addr((unsigned long)__gu_addr)) \ @@ -239,7 +246,7 @@ do { \ #define __get_user_check(x, ptr, size) \ ({ \ long __gu_err = -EFAULT; \ - unsigned long __gu_val = 0; \ + __long_type(*(ptr)) __gu_val = 0; \ const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ might_fault(); \ if (access_ok(VERIFY_READ, __gu_addr, (size))) \ @@ -251,7 +258,7 @@ do { \ #define __get_user_nosleep(x, ptr, size) \ ({ \ long __gu_err; \ - unsigned long __gu_val; \ + __long_type(*(ptr)) __gu_val; \ const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ __chk_user_ptr(ptr); \ __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \ diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index c09f0a6f84954260775a792c9b600d8a3210d2dd..f65bb53df43bf0e12ad586c1b049b0dc61f8aed1 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -1452,6 +1452,8 @@ TRAMP_REAL_BEGIN(stf_barrier_fallback) TRAMP_REAL_BEGIN(rfi_flush_fallback) SET_SCRATCH0(r13); GET_PACA(r13); + std r1,PACA_EXRFI+EX_R12(r13) + ld r1,PACAKSAVE(r13) std r9,PACA_EXRFI+EX_R9(r13) std r10,PACA_EXRFI+EX_R10(r13) std r11,PACA_EXRFI+EX_R11(r13) @@ -1486,12 +1488,15 @@ TRAMP_REAL_BEGIN(rfi_flush_fallback) ld r9,PACA_EXRFI+EX_R9(r13) ld r10,PACA_EXRFI+EX_R10(r13) ld r11,PACA_EXRFI+EX_R11(r13) + ld r1,PACA_EXRFI+EX_R12(r13) GET_SCRATCH0(r13); rfid TRAMP_REAL_BEGIN(hrfi_flush_fallback) SET_SCRATCH0(r13); GET_PACA(r13); + std r1,PACA_EXRFI+EX_R12(r13) + ld r1,PACAKSAVE(r13) std r9,PACA_EXRFI+EX_R9(r13) std r10,PACA_EXRFI+EX_R10(r13) std r11,PACA_EXRFI+EX_R11(r13) @@ -1526,6 +1531,7 @@ TRAMP_REAL_BEGIN(hrfi_flush_fallback) ld r9,PACA_EXRFI+EX_R9(r13) ld r10,PACA_EXRFI+EX_R10(r13) ld r11,PACA_EXRFI+EX_R11(r13) + ld r1,PACA_EXRFI+EX_R12(r13) GET_SCRATCH0(r13); hrfid diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c index d0020bc1f2095c6d1433dc390d30aa327b99a9e6..5a6470383ca3968af8b3f5d3eb0856238d746435 100644 --- a/arch/powerpc/kernel/fadump.c +++ b/arch/powerpc/kernel/fadump.c @@ -47,8 +47,10 @@ static struct fadump_mem_struct fdm; static const struct fadump_mem_struct *fdm_active; static DEFINE_MUTEX(fadump_mutex); -struct fad_crash_memory_ranges crash_memory_ranges[INIT_CRASHMEM_RANGES]; +struct fad_crash_memory_ranges *crash_memory_ranges; +int crash_memory_ranges_size; int crash_mem_ranges; +int max_crash_mem_ranges; /* Scan the Firmware Assisted dump configuration details. */ int __init early_init_dt_scan_fw_dump(unsigned long node, @@ -843,38 +845,88 @@ static int __init process_fadump(const struct fadump_mem_struct *fdm_active) return 0; } -static inline void fadump_add_crash_memory(unsigned long long base, - unsigned long long end) +static void free_crash_memory_ranges(void) +{ + kfree(crash_memory_ranges); + crash_memory_ranges = NULL; + crash_memory_ranges_size = 0; + max_crash_mem_ranges = 0; +} + +/* + * Allocate or reallocate crash memory ranges array in incremental units + * of PAGE_SIZE. + */ +static int allocate_crash_memory_ranges(void) +{ + struct fad_crash_memory_ranges *new_array; + u64 new_size; + + new_size = crash_memory_ranges_size + PAGE_SIZE; + pr_debug("Allocating %llu bytes of memory for crash memory ranges\n", + new_size); + + new_array = krealloc(crash_memory_ranges, new_size, GFP_KERNEL); + if (new_array == NULL) { + pr_err("Insufficient memory for setting up crash memory ranges\n"); + free_crash_memory_ranges(); + return -ENOMEM; + } + + crash_memory_ranges = new_array; + crash_memory_ranges_size = new_size; + max_crash_mem_ranges = (new_size / + sizeof(struct fad_crash_memory_ranges)); + return 0; +} + +static inline int fadump_add_crash_memory(unsigned long long base, + unsigned long long end) { if (base == end) - return; + return 0; + + if (crash_mem_ranges == max_crash_mem_ranges) { + int ret; + + ret = allocate_crash_memory_ranges(); + if (ret) + return ret; + } pr_debug("crash_memory_range[%d] [%#016llx-%#016llx], %#llx bytes\n", crash_mem_ranges, base, end - 1, (end - base)); crash_memory_ranges[crash_mem_ranges].base = base; crash_memory_ranges[crash_mem_ranges].size = end - base; crash_mem_ranges++; + return 0; } -static void fadump_exclude_reserved_area(unsigned long long start, +static int fadump_exclude_reserved_area(unsigned long long start, unsigned long long end) { unsigned long long ra_start, ra_end; + int ret = 0; ra_start = fw_dump.reserve_dump_area_start; ra_end = ra_start + fw_dump.reserve_dump_area_size; if ((ra_start < end) && (ra_end > start)) { if ((start < ra_start) && (end > ra_end)) { - fadump_add_crash_memory(start, ra_start); - fadump_add_crash_memory(ra_end, end); + ret = fadump_add_crash_memory(start, ra_start); + if (ret) + return ret; + + ret = fadump_add_crash_memory(ra_end, end); } else if (start < ra_start) { - fadump_add_crash_memory(start, ra_start); + ret = fadump_add_crash_memory(start, ra_start); } else if (ra_end < end) { - fadump_add_crash_memory(ra_end, end); + ret = fadump_add_crash_memory(ra_end, end); } } else - fadump_add_crash_memory(start, end); + ret = fadump_add_crash_memory(start, end); + + return ret; } static int fadump_init_elfcore_header(char *bufp) @@ -914,10 +966,11 @@ static int fadump_init_elfcore_header(char *bufp) * Traverse through memblock structure and setup crash memory ranges. These * ranges will be used create PT_LOAD program headers in elfcore header. */ -static void fadump_setup_crash_memory_ranges(void) +static int fadump_setup_crash_memory_ranges(void) { struct memblock_region *reg; unsigned long long start, end; + int ret; pr_debug("Setup crash memory ranges.\n"); crash_mem_ranges = 0; @@ -928,7 +981,9 @@ static void fadump_setup_crash_memory_ranges(void) * specified during fadump registration. We need to create a separate * program header for this chunk with the correct offset. */ - fadump_add_crash_memory(RMA_START, fw_dump.boot_memory_size); + ret = fadump_add_crash_memory(RMA_START, fw_dump.boot_memory_size); + if (ret) + return ret; for_each_memblock(memory, reg) { start = (unsigned long long)reg->base; @@ -948,8 +1003,12 @@ static void fadump_setup_crash_memory_ranges(void) } /* add this range excluding the reserved dump area. */ - fadump_exclude_reserved_area(start, end); + ret = fadump_exclude_reserved_area(start, end); + if (ret) + return ret; } + + return 0; } /* @@ -1072,6 +1131,7 @@ static int register_fadump(void) { unsigned long addr; void *vaddr; + int ret; /* * If no memory is reserved then we can not register for firmware- @@ -1080,7 +1140,9 @@ static int register_fadump(void) if (!fw_dump.reserve_dump_area_size) return -ENODEV; - fadump_setup_crash_memory_ranges(); + ret = fadump_setup_crash_memory_ranges(); + if (ret) + return ret; addr = be64_to_cpu(fdm.rmr_region.destination_address) + be64_to_cpu(fdm.rmr_region.source_len); /* Initialize fadump crash info header. */ @@ -1158,6 +1220,7 @@ void fadump_cleanup(void) } else if (fw_dump.dump_registered) { /* Un-register Firmware-assisted dump if it was registered. */ fadump_unregister_dump(&fdm); + free_crash_memory_ranges(); } } diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c index 2694d078741d08c9f32a05c7ea6323867ddde63d..9dafd7af39b8f517b68ab254e1ec134fffd993e8 100644 --- a/arch/powerpc/kernel/machine_kexec.c +++ b/arch/powerpc/kernel/machine_kexec.c @@ -186,7 +186,12 @@ void __init reserve_crashkernel(void) (unsigned long)(crashk_res.start >> 20), (unsigned long)(memblock_phys_mem_size() >> 20)); - memblock_reserve(crashk_res.start, crash_size); + if (!memblock_is_region_memory(crashk_res.start, crash_size) || + memblock_reserve(crashk_res.start, crash_size)) { + pr_err("Failed to reserve memory for crashkernel!\n"); + crashk_res.start = crashk_res.end = 0; + return; + } } int overlaps_crashkernel(unsigned long start, unsigned long size) diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c index df9b53f40b1eb71568716eb4dd44a52d5ccd815e..7ac7e21b137e2995cf0d5b7b80da11546300a209 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_hv.c +++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c @@ -355,7 +355,7 @@ static int kvmppc_mmu_book3s_64_hv_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, unsigned long pp, key; unsigned long v, orig_v, gr; __be64 *hptep; - int index; + long int index; int virtmode = vcpu->arch.shregs.msr & (data ? MSR_DR : MSR_IR); /* Get SLB entry */ diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 377d1420bd0243cc593e010657ac25351d9770b3..58746328b9bd6df7854973b5bea9fff040b2835c 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -4356,6 +4356,8 @@ static int kvmppc_book3s_init_hv(void) pr_err("KVM-HV: Cannot determine method for accessing XICS\n"); return -ENODEV; } + /* presence of intc confirmed - node can be dropped again */ + of_node_put(np); } #endif diff --git a/arch/powerpc/lib/code-patching.c b/arch/powerpc/lib/code-patching.c index 096d4e4d31e6359801f15d9b38f88d1ab275d0fc..882c750dc519eed90e057dbe75280fe0e0b7f488 100644 --- a/arch/powerpc/lib/code-patching.c +++ b/arch/powerpc/lib/code-patching.c @@ -22,20 +22,28 @@ #include #include #include +#include -static int __patch_instruction(unsigned int *addr, unsigned int instr) +static int __patch_instruction(unsigned int *exec_addr, unsigned int instr, + unsigned int *patch_addr) { int err; - __put_user_size(instr, addr, 4, err); + __put_user_size(instr, patch_addr, 4, err); if (err) return err; - asm ("dcbst 0, %0; sync; icbi 0,%0; sync; isync" :: "r" (addr)); + asm ("dcbst 0, %0; sync; icbi 0,%1; sync; isync" :: "r" (patch_addr), + "r" (exec_addr)); return 0; } +static int raw_patch_instruction(unsigned int *addr, unsigned int instr) +{ + return __patch_instruction(addr, instr, addr); +} + #ifdef CONFIG_STRICT_KERNEL_RWX static DEFINE_PER_CPU(struct vm_struct *, text_poke_area); @@ -135,10 +143,10 @@ static inline int unmap_patch_area(unsigned long addr) return 0; } -int patch_instruction(unsigned int *addr, unsigned int instr) +static int do_patch_instruction(unsigned int *addr, unsigned int instr) { int err; - unsigned int *dest = NULL; + unsigned int *patch_addr = NULL; unsigned long flags; unsigned long text_poke_addr; unsigned long kaddr = (unsigned long)addr; @@ -149,7 +157,7 @@ int patch_instruction(unsigned int *addr, unsigned int instr) * to allow patching. We just do the plain old patching */ if (!this_cpu_read(*PTRRELOC(&text_poke_area))) - return __patch_instruction(addr, instr); + return raw_patch_instruction(addr, instr); local_irq_save(flags); @@ -159,17 +167,10 @@ int patch_instruction(unsigned int *addr, unsigned int instr) goto out; } - dest = (unsigned int *)(text_poke_addr) + + patch_addr = (unsigned int *)(text_poke_addr) + ((kaddr & ~PAGE_MASK) / sizeof(unsigned int)); - /* - * We use __put_user_size so that we can handle faults while - * writing to dest and return err to handle faults gracefully - */ - __put_user_size(instr, dest, 4, err); - if (!err) - asm ("dcbst 0, %0; sync; icbi 0,%0; icbi 0,%1; sync; isync" - ::"r" (dest), "r"(addr)); + __patch_instruction(addr, instr, patch_addr); err = unmap_patch_area(text_poke_addr); if (err) @@ -182,12 +183,22 @@ int patch_instruction(unsigned int *addr, unsigned int instr) } #else /* !CONFIG_STRICT_KERNEL_RWX */ -int patch_instruction(unsigned int *addr, unsigned int instr) +static int do_patch_instruction(unsigned int *addr, unsigned int instr) { - return __patch_instruction(addr, instr); + return raw_patch_instruction(addr, instr); } #endif /* CONFIG_STRICT_KERNEL_RWX */ + +int patch_instruction(unsigned int *addr, unsigned int instr) +{ + /* Make sure we aren't patching a freed init section */ + if (init_mem_is_free && init_section_contains(addr, 4)) { + pr_debug("Skipping init section patching addr: 0x%px\n", addr); + return 0; + } + return do_patch_instruction(addr, instr); +} NOKPROBE_SYMBOL(patch_instruction); int patch_branch(unsigned int *addr, unsigned long target, int flags) diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 9c2f83331e5b75cadf31e33ee1846e3e27c4cc23..30bf13b72e5e5740560fc562aaeee951040e0a92 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -63,6 +63,7 @@ #endif unsigned long long memory_limit; +bool init_mem_is_free; #ifdef CONFIG_HIGHMEM pte_t *kmap_pte; @@ -405,6 +406,7 @@ void free_initmem(void) { ppc_md.progress = ppc_printk_progress; mark_initmem_nx(); + init_mem_is_free = true; free_initmem_default(POISON_FREE_INITMEM); } diff --git a/arch/powerpc/mm/mmu_context_iommu.c b/arch/powerpc/mm/mmu_context_iommu.c index 816055927ee47ba05db7e1d3675461de66052636..d735937d975c8dca1b32f021e04ecb5fb47e703c 100644 --- a/arch/powerpc/mm/mmu_context_iommu.c +++ b/arch/powerpc/mm/mmu_context_iommu.c @@ -130,6 +130,7 @@ long mm_iommu_get(struct mm_struct *mm, unsigned long ua, unsigned long entries, long i, j, ret = 0, locked_entries = 0; unsigned int pageshift; unsigned long flags; + unsigned long cur_ua; struct page *page = NULL; mutex_lock(&mem_list_mutex); @@ -178,7 +179,8 @@ long mm_iommu_get(struct mm_struct *mm, unsigned long ua, unsigned long entries, } for (i = 0; i < entries; ++i) { - if (1 != get_user_pages_fast(ua + (i << PAGE_SHIFT), + cur_ua = ua + (i << PAGE_SHIFT); + if (1 != get_user_pages_fast(cur_ua, 1/* pages */, 1/* iswrite */, &page)) { ret = -EFAULT; for (j = 0; j < i; ++j) @@ -197,7 +199,7 @@ long mm_iommu_get(struct mm_struct *mm, unsigned long ua, unsigned long entries, if (is_migrate_cma_page(page)) { if (mm_iommu_move_page_from_cma(page)) goto populate; - if (1 != get_user_pages_fast(ua + (i << PAGE_SHIFT), + if (1 != get_user_pages_fast(cur_ua, 1/* pages */, 1/* iswrite */, &page)) { ret = -EFAULT; @@ -211,20 +213,21 @@ long mm_iommu_get(struct mm_struct *mm, unsigned long ua, unsigned long entries, } populate: pageshift = PAGE_SHIFT; - if (PageCompound(page)) { + if (mem->pageshift > PAGE_SHIFT && PageCompound(page)) { pte_t *pte; struct page *head = compound_head(page); unsigned int compshift = compound_order(head); + unsigned int pteshift; local_irq_save(flags); /* disables as well */ - pte = find_linux_pte(mm->pgd, ua, NULL, &pageshift); - local_irq_restore(flags); + pte = find_linux_pte(mm->pgd, cur_ua, NULL, &pteshift); /* Double check it is still the same pinned page */ if (pte && pte_page(*pte) == head && - pageshift == compshift) - pageshift = max_t(unsigned int, pageshift, + pteshift == compshift + PAGE_SHIFT) + pageshift = max_t(unsigned int, pteshift, PAGE_SHIFT); + local_irq_restore(flags); } mem->pageshift = min(mem->pageshift, pageshift); mem->hpas[i] = page_to_pfn(page) << PAGE_SHIFT; diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c index 254634fb3fc75198b037c3a8e68da1baf16ac424..fee1e1f8c9d3a059db0144009cf523bc69c1854e 100644 --- a/arch/powerpc/net/bpf_jit_comp64.c +++ b/arch/powerpc/net/bpf_jit_comp64.c @@ -322,6 +322,7 @@ static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u64 imm64; u8 *func; u32 true_cond; + u32 tmp_idx; /* * addrs[] maps a BPF bytecode address into a real offset from @@ -681,11 +682,7 @@ static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, case BPF_STX | BPF_XADD | BPF_W: /* Get EA into TMP_REG_1 */ PPC_ADDI(b2p[TMP_REG_1], dst_reg, off); - /* error if EA is not word-aligned */ - PPC_ANDI(b2p[TMP_REG_2], b2p[TMP_REG_1], 0x03); - PPC_BCC_SHORT(COND_EQ, (ctx->idx * 4) + 12); - PPC_LI(b2p[BPF_REG_0], 0); - PPC_JMP(exit_addr); + tmp_idx = ctx->idx * 4; /* load value from memory into TMP_REG_2 */ PPC_BPF_LWARX(b2p[TMP_REG_2], 0, b2p[TMP_REG_1], 0); /* add value from src_reg into this */ @@ -693,32 +690,16 @@ static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, /* store result back */ PPC_BPF_STWCX(b2p[TMP_REG_2], 0, b2p[TMP_REG_1]); /* we're done if this succeeded */ - PPC_BCC_SHORT(COND_EQ, (ctx->idx * 4) + (7*4)); - /* otherwise, let's try once more */ - PPC_BPF_LWARX(b2p[TMP_REG_2], 0, b2p[TMP_REG_1], 0); - PPC_ADD(b2p[TMP_REG_2], b2p[TMP_REG_2], src_reg); - PPC_BPF_STWCX(b2p[TMP_REG_2], 0, b2p[TMP_REG_1]); - /* exit if the store was not successful */ - PPC_LI(b2p[BPF_REG_0], 0); - PPC_BCC(COND_NE, exit_addr); + PPC_BCC_SHORT(COND_NE, tmp_idx); break; /* *(u64 *)(dst + off) += src */ case BPF_STX | BPF_XADD | BPF_DW: PPC_ADDI(b2p[TMP_REG_1], dst_reg, off); - /* error if EA is not doubleword-aligned */ - PPC_ANDI(b2p[TMP_REG_2], b2p[TMP_REG_1], 0x07); - PPC_BCC_SHORT(COND_EQ, (ctx->idx * 4) + (3*4)); - PPC_LI(b2p[BPF_REG_0], 0); - PPC_JMP(exit_addr); - PPC_BPF_LDARX(b2p[TMP_REG_2], 0, b2p[TMP_REG_1], 0); - PPC_ADD(b2p[TMP_REG_2], b2p[TMP_REG_2], src_reg); - PPC_BPF_STDCX(b2p[TMP_REG_2], 0, b2p[TMP_REG_1]); - PPC_BCC_SHORT(COND_EQ, (ctx->idx * 4) + (7*4)); + tmp_idx = ctx->idx * 4; PPC_BPF_LDARX(b2p[TMP_REG_2], 0, b2p[TMP_REG_1], 0); PPC_ADD(b2p[TMP_REG_2], b2p[TMP_REG_2], src_reg); PPC_BPF_STDCX(b2p[TMP_REG_2], 0, b2p[TMP_REG_1]); - PPC_LI(b2p[BPF_REG_0], 0); - PPC_BCC(COND_NE, exit_addr); + PPC_BCC_SHORT(COND_NE, tmp_idx); break; /* diff --git a/arch/powerpc/platforms/85xx/t1042rdb_diu.c b/arch/powerpc/platforms/85xx/t1042rdb_diu.c index 58fa3d319f1c118247732b6d2e7e7583279ea450..dac36ba82fea8555576cd63c4d2e29c343b605da 100644 --- a/arch/powerpc/platforms/85xx/t1042rdb_diu.c +++ b/arch/powerpc/platforms/85xx/t1042rdb_diu.c @@ -9,8 +9,10 @@ * option) any later version. */ +#include #include #include +#include #include #include @@ -150,3 +152,5 @@ static int __init t1042rdb_diu_init(void) } early_initcall(t1042rdb_diu_init); + +MODULE_LICENSE("GPL"); diff --git a/arch/powerpc/platforms/powernv/npu-dma.c b/arch/powerpc/platforms/powernv/npu-dma.c index 63f007f2de7eb295b9bb78821e2dca596a96e56f..4b95bdde22aa7874499a1a9b4e71c691798d72b1 100644 --- a/arch/powerpc/platforms/powernv/npu-dma.c +++ b/arch/powerpc/platforms/powernv/npu-dma.c @@ -427,8 +427,9 @@ static int get_mmio_atsd_reg(struct npu *npu) int i; for (i = 0; i < npu->mmio_atsd_count; i++) { - if (!test_and_set_bit_lock(i, &npu->mmio_atsd_usage)) - return i; + if (!test_bit(i, &npu->mmio_atsd_usage)) + if (!test_and_set_bit_lock(i, &npu->mmio_atsd_usage)) + return i; } return -ENOSPC; diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index 65c79ecf5a4d685c3c2d5035a18b196bb9664f63..c8a743af6bf507d2a0f2d63e34bb20234a275d83 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -388,7 +388,7 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len) /* Closed or other error drop */ if (rc != OPAL_SUCCESS && rc != OPAL_BUSY && rc != OPAL_BUSY_EVENT) { - written = total_len; + written += total_len; break; } if (rc == OPAL_SUCCESS) { diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 677b29ef4532b15c8dfa2aec01b2405ced8454f3..ddef22e00ddd74e84e38ec2c6ec2193e36741112 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -2787,7 +2787,7 @@ static long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset, level_shift = entries_shift + 3; level_shift = max_t(unsigned, level_shift, PAGE_SHIFT); - if ((level_shift - 3) * levels + page_shift >= 60) + if ((level_shift - 3) * levels + page_shift >= 55) return -EINVAL; /* Allocate TCE table */ @@ -3286,12 +3286,49 @@ static void pnv_pci_ioda_create_dbgfs(void) #endif /* CONFIG_DEBUG_FS */ } +static void pnv_pci_enable_bridge(struct pci_bus *bus) +{ + struct pci_dev *dev = bus->self; + struct pci_bus *child; + + /* Empty bus ? bail */ + if (list_empty(&bus->devices)) + return; + + /* + * If there's a bridge associated with that bus enable it. This works + * around races in the generic code if the enabling is done during + * parallel probing. This can be removed once those races have been + * fixed. + */ + if (dev) { + int rc = pci_enable_device(dev); + if (rc) + pci_err(dev, "Error enabling bridge (%d)\n", rc); + pci_set_master(dev); + } + + /* Perform the same to child busses */ + list_for_each_entry(child, &bus->children, node) + pnv_pci_enable_bridge(child); +} + +static void pnv_pci_enable_bridges(void) +{ + struct pci_controller *hose; + + list_for_each_entry(hose, &hose_list, list_node) + pnv_pci_enable_bridge(hose->bus); +} + static void pnv_pci_ioda_fixup(void) { pnv_pci_ioda_setup_PEs(); pnv_pci_ioda_setup_iommu_api(); pnv_pci_ioda_create_dbgfs(); + pnv_pci_enable_bridges(); + #ifdef CONFIG_EEH eeh_init(); eeh_addr_cache_build(); diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index 5e1ef915018208c3511ef0e91c0064c8c9474389..99d1152ae22413a5b8139ad9c9f0d9328a96d336 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -360,7 +360,7 @@ static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs) } savep = __va(regs->gpr[3]); - regs->gpr[3] = savep[0]; /* restore original r3 */ + regs->gpr[3] = be64_to_cpu(savep[0]); /* restore original r3 */ /* If it isn't an extended log we can use the per cpu 64bit buffer */ h = (struct rtas_error_log *)&savep[1]; @@ -371,7 +371,7 @@ static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs) int len, error_log_length; error_log_length = 8 + rtas_error_extended_log_length(h); - len = max_t(int, error_log_length, RTAS_ERROR_LOG_MAX); + len = min_t(int, error_log_length, RTAS_ERROR_LOG_MAX); memset(global_mce_data_buf, 0, RTAS_ERROR_LOG_MAX); memcpy(global_mce_data_buf, h, len); errhdr = (struct rtas_error_log *)global_mce_data_buf; diff --git a/arch/powerpc/sysdev/mpic_msgr.c b/arch/powerpc/sysdev/mpic_msgr.c index eb69a51862431cccc81034f1fb9a1c8decc906d2..280e964e1aa8873db4491f42df93ddc115e85509 100644 --- a/arch/powerpc/sysdev/mpic_msgr.c +++ b/arch/powerpc/sysdev/mpic_msgr.c @@ -196,7 +196,7 @@ static int mpic_msgr_probe(struct platform_device *dev) /* IO map the message register block. */ of_address_to_resource(np, 0, &rsrc); - msgr_block_addr = ioremap(rsrc.start, rsrc.end - rsrc.start); + msgr_block_addr = ioremap(rsrc.start, resource_size(&rsrc)); if (!msgr_block_addr) { dev_err(&dev->dev, "Failed to iomap MPIC message registers"); return -EFAULT; diff --git a/arch/s390/crypto/paes_s390.c b/arch/s390/crypto/paes_s390.c index a4e903ed7e21c0ccc7ceb66944ac6b43662003ea..b429aceff050a7bfd6d7abcf68cd95c08d6238ba 100644 --- a/arch/s390/crypto/paes_s390.c +++ b/arch/s390/crypto/paes_s390.c @@ -212,7 +212,7 @@ static int cbc_paes_crypt(struct blkcipher_desc *desc, unsigned long modifier, walk->dst.virt.addr, walk->src.virt.addr, n); if (k) ret = blkcipher_walk_done(desc, walk, nbytes - k); - if (n < k) { + if (k < n) { if (__cbc_paes_set_key(ctx) != 0) return blkcipher_walk_done(desc, walk, -EIO); memcpy(param.key, ctx->pk.protkey, MAXPROTKEYSIZE); diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h index de11ecc99c7c46cf967a96c573f1a6c6d2cafc46..9c9970a5dfb10798ddd459dbcff7beae2d9ea42c 100644 --- a/arch/s390/include/asm/qdio.h +++ b/arch/s390/include/asm/qdio.h @@ -262,7 +262,6 @@ struct qdio_outbuf_state { void *user; }; -#define QDIO_OUTBUF_STATE_FLAG_NONE 0x00 #define QDIO_OUTBUF_STATE_FLAG_PENDING 0x01 #define CHSC_AC1_INITIATE_INPUTQ 0x80 diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c index 9f5ea9d870690aea40742e4d5b3181bb637623cc..9b0216d571adc04b6bb9876c14d756cb297a4bbc 100644 --- a/arch/s390/kernel/crash_dump.c +++ b/arch/s390/kernel/crash_dump.c @@ -404,11 +404,13 @@ static void *get_vmcoreinfo_old(unsigned long *size) if (copy_oldmem_kernel(nt_name, addr + sizeof(note), sizeof(nt_name) - 1)) return NULL; - if (strcmp(nt_name, "VMCOREINFO") != 0) + if (strcmp(nt_name, VMCOREINFO_NOTE_NAME) != 0) return NULL; vmcoreinfo = kzalloc_panic(note.n_descsz); - if (copy_oldmem_kernel(vmcoreinfo, addr + 24, note.n_descsz)) + if (copy_oldmem_kernel(vmcoreinfo, addr + 24, note.n_descsz)) { + kfree(vmcoreinfo); return NULL; + } *size = note.n_descsz; return vmcoreinfo; } @@ -418,15 +420,20 @@ static void *get_vmcoreinfo_old(unsigned long *size) */ static void *nt_vmcoreinfo(void *ptr) { + const char *name = VMCOREINFO_NOTE_NAME; unsigned long size; void *vmcoreinfo; vmcoreinfo = os_info_old_entry(OS_INFO_VMCOREINFO, &size); - if (!vmcoreinfo) - vmcoreinfo = get_vmcoreinfo_old(&size); + if (vmcoreinfo) + return nt_init_name(ptr, 0, vmcoreinfo, size, name); + + vmcoreinfo = get_vmcoreinfo_old(&size); if (!vmcoreinfo) return ptr; - return nt_init_name(ptr, 0, vmcoreinfo, size, "VMCOREINFO"); + ptr = nt_init_name(ptr, 0, vmcoreinfo, size, name); + kfree(vmcoreinfo); + return ptr; } /* diff --git a/arch/s390/kernel/sysinfo.c b/arch/s390/kernel/sysinfo.c index a441cba8d165c5c034cfa5bb72628eaf885f1498..b0fad29c1427fccf76584e6d434ca83d6d877949 100644 --- a/arch/s390/kernel/sysinfo.c +++ b/arch/s390/kernel/sysinfo.c @@ -59,6 +59,8 @@ int stsi(void *sysinfo, int fc, int sel1, int sel2) } EXPORT_SYMBOL(stsi); +#ifdef CONFIG_PROC_FS + static bool convert_ext_name(unsigned char encoding, char *name, size_t len) { switch (encoding) { @@ -311,6 +313,8 @@ static int __init sysinfo_create_proc(void) } device_initcall(sysinfo_create_proc); +#endif /* CONFIG_PROC_FS */ + /* * Service levels interface. */ diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index 4f1f5fc8139d881078720f42f4e6d907ee3fa342..061906f98dc5cc95cd3c965535d0dd9cb2083a9e 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -170,7 +170,8 @@ static int shadow_crycb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) return set_validity_icpt(scb_s, 0x0039U); /* copy only the wrapping keys */ - if (read_guest_real(vcpu, crycb_addr + 72, &vsie_page->crycb, 56)) + if (read_guest_real(vcpu, crycb_addr + 72, + vsie_page->crycb.dea_wrapping_key_mask, 56)) return set_validity_icpt(scb_s, 0x0035U); scb_s->ecb3 |= ecb3_flags; diff --git a/arch/s390/lib/mem.S b/arch/s390/lib/mem.S index e1fa974ac5005e7909996d9075fd30c13964cd8a..37e52118d7e9ef23ed28701f67a41514caf40605 100644 --- a/arch/s390/lib/mem.S +++ b/arch/s390/lib/mem.S @@ -17,7 +17,7 @@ ENTRY(memmove) ltgr %r4,%r4 lgr %r1,%r2 - bzr %r14 + jz .Lmemmove_exit aghi %r4,-1 clgr %r2,%r3 jnh .Lmemmove_forward @@ -36,6 +36,7 @@ ENTRY(memmove) .Lmemmove_forward_remainder: larl %r5,.Lmemmove_mvc ex %r4,0(%r5) +.Lmemmove_exit: BR_EX %r14 .Lmemmove_reverse: ic %r0,0(%r4,%r3) @@ -65,7 +66,7 @@ EXPORT_SYMBOL(memmove) */ ENTRY(memset) ltgr %r4,%r4 - bzr %r14 + jz .Lmemset_exit ltgr %r3,%r3 jnz .Lmemset_fill aghi %r4,-1 @@ -80,12 +81,13 @@ ENTRY(memset) .Lmemset_clear_remainder: larl %r3,.Lmemset_xc ex %r4,0(%r3) +.Lmemset_exit: BR_EX %r14 .Lmemset_fill: stc %r3,0(%r2) cghi %r4,1 lgr %r1,%r2 - ber %r14 + je .Lmemset_fill_exit aghi %r4,-2 srlg %r3,%r4,8 ltgr %r3,%r3 @@ -97,6 +99,7 @@ ENTRY(memset) .Lmemset_fill_remainder: larl %r3,.Lmemset_mvc ex %r4,0(%r3) +.Lmemset_fill_exit: BR_EX %r14 .Lmemset_xc: xc 0(1,%r1),0(%r1) @@ -111,7 +114,7 @@ EXPORT_SYMBOL(memset) */ ENTRY(memcpy) ltgr %r4,%r4 - bzr %r14 + jz .Lmemcpy_exit aghi %r4,-1 srlg %r5,%r4,8 ltgr %r5,%r5 @@ -120,6 +123,7 @@ ENTRY(memcpy) .Lmemcpy_remainder: larl %r5,.Lmemcpy_mvc ex %r4,0(%r5) +.Lmemcpy_exit: BR_EX %r14 .Lmemcpy_loop: mvc 0(256,%r1),0(%r3) diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index 920d408945359351e20e2ae397598390a0ad2f27..290e71e57541cb4c7b1c512aff333797e31684ee 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c @@ -80,7 +80,7 @@ struct qin64 { struct dcss_segment { struct list_head list; char dcss_name[8]; - char res_name[15]; + char res_name[16]; unsigned long start_addr; unsigned long end; atomic_t ref_count; @@ -433,7 +433,7 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long memcpy(&seg->res_name, seg->dcss_name, 8); EBCASC(seg->res_name, 8); seg->res_name[8] = '\0'; - strncat(seg->res_name, " (DCSS)", 7); + strlcat(seg->res_name, " (DCSS)", sizeof(seg->res_name)); seg->res->name = seg->res_name; rc = seg->vm_segtype; if (rc == SEG_TYPE_SC || diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 242b78c0a9ec84ba7a956d197cdd887bf86c9ebd..40f1888bc4ab7d9504d47190ac36a1692aa3671b 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -486,6 +486,8 @@ static inline int do_exception(struct pt_regs *regs, int access) /* No reason to continue if interrupted by SIGKILL. */ if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) { fault = VM_FAULT_SIGNAL; + if (flags & FAULT_FLAG_RETRY_NOWAIT) + goto out_up; goto out; } if (unlikely(fault & VM_FAULT_ERROR)) diff --git a/arch/s390/mm/page-states.c b/arch/s390/mm/page-states.c index 382153ff17e30e5203b217654d6b25fa0ddd78e6..dc3cede7f2ec9df1a886fc3e92821f2b7f9c6195 100644 --- a/arch/s390/mm/page-states.c +++ b/arch/s390/mm/page-states.c @@ -271,7 +271,7 @@ void arch_set_page_states(int make_stable) list_for_each(l, &zone->free_area[order].free_list[t]) { page = list_entry(l, struct page, lru); if (make_stable) - set_page_stable_dat(page, 0); + set_page_stable_dat(page, order); else set_page_unused(page, order); } diff --git a/arch/s390/mm/pgalloc.c b/arch/s390/mm/pgalloc.c index 334b6d103cbd191ce877f7a65b696d1384de96e2..29653f713162d3f2d2377ce55aef5f754f98452f 100644 --- a/arch/s390/mm/pgalloc.c +++ b/arch/s390/mm/pgalloc.c @@ -27,7 +27,7 @@ static struct ctl_table page_table_sysctl[] = { .data = &page_table_allocate_pgste, .maxlen = sizeof(int), .mode = S_IRUGO | S_IWUSR, - .proc_handler = proc_dointvec, + .proc_handler = proc_dointvec_minmax, .extra1 = &page_table_allocate_pgste_min, .extra2 = &page_table_allocate_pgste_max, }, diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c index 11cd151733d43a4a8e9d0c992a4005ca8dc1e509..6b1474fa99ab3f98f68227fa97fc4d0768445ac3 100644 --- a/arch/s390/net/bpf_jit_comp.c +++ b/arch/s390/net/bpf_jit_comp.c @@ -518,8 +518,6 @@ static void bpf_jit_epilogue(struct bpf_jit *jit) /* br %r1 */ _EMIT2(0x07f1); } else { - /* larl %r1,.+14 */ - EMIT6_PCREL_RILB(0xc0000000, REG_1, jit->prg + 14); /* ex 0,S390_lowcore.br_r1_tampoline */ EMIT4_DISP(0x44000000, REG_0, REG_0, offsetof(struct lowcore, br_r1_trampoline)); @@ -1403,6 +1401,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp) goto free_addrs; } if (bpf_jit_prog(&jit, fp)) { + bpf_jit_binary_free(header); fp = orig_fp; goto free_addrs; } diff --git a/arch/s390/numa/numa.c b/arch/s390/numa/numa.c index 06a80434cfe63f69c7c7ff2e86caba734161484e..5bd374491f9461467790e1e0522f838827f094df 100644 --- a/arch/s390/numa/numa.c +++ b/arch/s390/numa/numa.c @@ -134,26 +134,14 @@ void __init numa_setup(void) { pr_info("NUMA mode: %s\n", mode->name); nodes_clear(node_possible_map); + /* Initially attach all possible CPUs to node 0. */ + cpumask_copy(&node_to_cpumask_map[0], cpu_possible_mask); if (mode->setup) mode->setup(); numa_setup_memory(); memblock_dump_all(); } -/* - * numa_init_early() - Initialization initcall - * - * This runs when only one CPU is online and before the first - * topology update is called for by the scheduler. - */ -static int __init numa_init_early(void) -{ - /* Attach all possible CPUs to node 0 for now. */ - cpumask_copy(&node_to_cpumask_map[0], cpu_possible_mask); - return 0; -} -early_initcall(numa_init_early); - /* * numa_init_late() - Initialization initcall * diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index 0fe649c0d5423a2ed51fcff4dc7d011204fdf4e9..960c4a362d8cdeb525bf020729cd8007bfa836ec 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c @@ -420,6 +420,8 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) hwirq = 0; for_each_pci_msi_entry(msi, pdev) { rc = -EIO; + if (hwirq >= msi_vecs) + break; irq = irq_alloc_desc(0); /* Alloc irq on node 0 */ if (irq < 0) return -ENOMEM; diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild index 80ddc01f57ac347957a2e05348ada69ca47e226f..fcbc0c0aa087db6adfb91a4b40c6a666922ae96f 100644 --- a/arch/sparc/include/asm/Kbuild +++ b/arch/sparc/include/asm/Kbuild @@ -14,6 +14,7 @@ generic-y += local64.h generic-y += mcs_spinlock.h generic-y += mm-arch-hooks.h generic-y += module.h +generic-y += msi.h generic-y += preempt.h generic-y += rwsem.h generic-y += serial.h diff --git a/arch/sparc/kernel/sys_sparc_32.c b/arch/sparc/kernel/sys_sparc_32.c index 990703b7cf4d7d47d26152e510706bc32528d488..4b7719b2a73c671d35412d27334c62001e32a866 100644 --- a/arch/sparc/kernel/sys_sparc_32.c +++ b/arch/sparc/kernel/sys_sparc_32.c @@ -204,23 +204,27 @@ SYSCALL_DEFINE5(rt_sigaction, int, sig, asmlinkage long sys_getdomainname(char __user *name, int len) { - int nlen, err; - + int nlen, err; + char tmp[__NEW_UTS_LEN + 1]; + if (len < 0) return -EINVAL; - down_read(&uts_sem); - + down_read(&uts_sem); + nlen = strlen(utsname()->domainname) + 1; err = -EINVAL; if (nlen > len) - goto out; + goto out_unlock; + memcpy(tmp, utsname()->domainname, nlen); - err = -EFAULT; - if (!copy_to_user(name, utsname()->domainname, nlen)) - err = 0; + up_read(&uts_sem); -out: + if (copy_to_user(name, tmp, nlen)) + return -EFAULT; + return 0; + +out_unlock: up_read(&uts_sem); return err; } diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c index 55416db482add475baf4c2fc312605577442470f..d79c1c74873cfdcf0ac3e26c521a4623508d14dc 100644 --- a/arch/sparc/kernel/sys_sparc_64.c +++ b/arch/sparc/kernel/sys_sparc_64.c @@ -527,23 +527,27 @@ extern void check_pending(int signum); SYSCALL_DEFINE2(getdomainname, char __user *, name, int, len) { - int nlen, err; + int nlen, err; + char tmp[__NEW_UTS_LEN + 1]; if (len < 0) return -EINVAL; - down_read(&uts_sem); - + down_read(&uts_sem); + nlen = strlen(utsname()->domainname) + 1; err = -EINVAL; if (nlen > len) - goto out; + goto out_unlock; + memcpy(tmp, utsname()->domainname, nlen); + + up_read(&uts_sem); - err = -EFAULT; - if (!copy_to_user(name, utsname()->domainname, nlen)) - err = 0; + if (copy_to_user(name, tmp, nlen)) + return -EFAULT; + return 0; -out: +out_unlock: up_read(&uts_sem); return err; } diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c index 3b397081047af69a23b6672917e1706786d3134f..83aaf4888999281a3c20f19c014a13d7b7521d65 100644 --- a/arch/sparc/kernel/time_64.c +++ b/arch/sparc/kernel/time_64.c @@ -813,7 +813,7 @@ static void __init get_tick_patch(void) } } -static void init_tick_ops(struct sparc64_tick_ops *ops) +static void __init init_tick_ops(struct sparc64_tick_ops *ops) { unsigned long freq, quotient, tick; diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 7483cd514c32555dffb43aef80c7c699218e5cd1..2af0af33362a6c8cf3f000da56af9679d1ce952e 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -170,12 +170,14 @@ config X86 select HAVE_PERF_REGS select HAVE_PERF_USER_STACK_DUMP select HAVE_RCU_TABLE_FREE + select HAVE_RCU_TABLE_INVALIDATE if HAVE_RCU_TABLE_FREE select HAVE_REGS_AND_STACK_ACCESS_API select HAVE_RELIABLE_STACKTRACE if X86_64 && UNWINDER_FRAME_POINTER && STACK_VALIDATION select HAVE_STACK_VALIDATION if X86_64 select HAVE_SYSCALL_TRACEPOINTS select HAVE_UNSTABLE_SCHED_CLOCK select HAVE_USER_RETURN_NOTIFIER + select HOTPLUG_SMT if SMP select IRQ_FORCED_THREADING select PCI_LOCKLESS_CONFIG select PERF_EVENTS diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 98018a621f6b0c4d0dcc32fed7e5ac94c7d3cf93..3a250ca2406c0d606f6386cdded977b56ddccffc 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -104,9 +104,13 @@ define cmd_check_data_rel done endef +# We need to run two commands under "if_changed", so merge them into a +# single invocation. +quiet_cmd_check-and-link-vmlinux = LD $@ + cmd_check-and-link-vmlinux = $(cmd_check_data_rel); $(cmd_ld) + $(obj)/vmlinux: $(vmlinux-objs-y) FORCE - $(call if_changed,check_data_rel) - $(call if_changed,ld) + $(call if_changed,check-and-link-vmlinux) OBJCOPYFLAGS_vmlinux.bin := -R .comment -S $(obj)/vmlinux.bin: vmlinux FORCE diff --git a/arch/x86/crypto/sha256-mb/sha256_mb_mgr_flush_avx2.S b/arch/x86/crypto/sha256-mb/sha256_mb_mgr_flush_avx2.S index 16c4ccb1f154883017062c90d7ca0fc22dc67e29..d2364c55bbdeb6513730e646183cf7a925eac1e2 100644 --- a/arch/x86/crypto/sha256-mb/sha256_mb_mgr_flush_avx2.S +++ b/arch/x86/crypto/sha256-mb/sha256_mb_mgr_flush_avx2.S @@ -265,7 +265,7 @@ ENTRY(sha256_mb_mgr_get_comp_job_avx2) vpinsrd $1, _args_digest+1*32(state, idx, 4), %xmm0, %xmm0 vpinsrd $2, _args_digest+2*32(state, idx, 4), %xmm0, %xmm0 vpinsrd $3, _args_digest+3*32(state, idx, 4), %xmm0, %xmm0 - vmovd _args_digest(state , idx, 4) , %xmm0 + vmovd _args_digest+4*32(state, idx, 4), %xmm1 vpinsrd $1, _args_digest+5*32(state, idx, 4), %xmm1, %xmm1 vpinsrd $2, _args_digest+6*32(state, idx, 4), %xmm1, %xmm1 vpinsrd $3, _args_digest+7*32(state, idx, 4), %xmm1, %xmm1 diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index 0fae7096ae23cc5372cc78fa43ebfaa84f0e66a7..164cd7529f0b080a0993797f9260ada24ca75d82 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -88,7 +88,7 @@ END(native_usergs_sysret64) .endm .macro TRACE_IRQS_IRETQ_DEBUG - bt $9, EFLAGS(%rsp) /* interrupts off? */ + btl $9, EFLAGS(%rsp) /* interrupts off? */ jnc 1f TRACE_IRQS_ON_DEBUG 1: @@ -630,7 +630,7 @@ retint_kernel: #ifdef CONFIG_PREEMPT /* Interrupts are off */ /* Check if we need preemption */ - bt $9, EFLAGS(%rsp) /* were interrupts off? */ + btl $9, EFLAGS(%rsp) /* were interrupts off? */ jnc 1f 0: cmpl $0, PER_CPU_VAR(__preempt_count) jnz 1f diff --git a/arch/x86/entry/vdso/Makefile b/arch/x86/entry/vdso/Makefile index f5c1007e2c408bf484ac816fd8ffe1f6bd506723..4505ffe2a505f29dc46f7a32acfcd8a9a9dc9523 100644 --- a/arch/x86/entry/vdso/Makefile +++ b/arch/x86/entry/vdso/Makefile @@ -76,7 +76,13 @@ CFL := $(PROFILING) -mcmodel=small -fPIC -O2 -fasynchronous-unwind-tables -m64 \ -fno-omit-frame-pointer -foptimize-sibling-calls \ -DDISABLE_BRANCH_PROFILING -DBUILD_VDSO -$(vobjs): KBUILD_CFLAGS := $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS)) $(CFL) +ifdef CONFIG_RETPOLINE +ifneq ($(RETPOLINE_VDSO_CFLAGS),) + CFL += $(RETPOLINE_VDSO_CFLAGS) +endif +endif + +$(vobjs): KBUILD_CFLAGS := $(filter-out $(GCC_PLUGINS_CFLAGS) $(RETPOLINE_CFLAGS),$(KBUILD_CFLAGS)) $(CFL) # # vDSO code runs in userspace and -pg doesn't help with profiling anyway. @@ -147,11 +153,19 @@ KBUILD_CFLAGS_32 := $(filter-out -mcmodel=kernel,$(KBUILD_CFLAGS_32)) KBUILD_CFLAGS_32 := $(filter-out -fno-pic,$(KBUILD_CFLAGS_32)) KBUILD_CFLAGS_32 := $(filter-out -mfentry,$(KBUILD_CFLAGS_32)) KBUILD_CFLAGS_32 := $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS_32)) +KBUILD_CFLAGS_32 := $(filter-out $(RETPOLINE_CFLAGS),$(KBUILD_CFLAGS_32)) KBUILD_CFLAGS_32 += -m32 -msoft-float -mregparm=0 -fpic KBUILD_CFLAGS_32 += $(call cc-option, -fno-stack-protector) KBUILD_CFLAGS_32 += $(call cc-option, -foptimize-sibling-calls) KBUILD_CFLAGS_32 += -fno-omit-frame-pointer KBUILD_CFLAGS_32 += -DDISABLE_BRANCH_PROFILING + +ifdef CONFIG_RETPOLINE +ifneq ($(RETPOLINE_VDSO_CFLAGS),) + KBUILD_CFLAGS_32 += $(RETPOLINE_VDSO_CFLAGS) +endif +endif + $(obj)/vdso32.so.dbg: KBUILD_CFLAGS = $(KBUILD_CFLAGS_32) $(obj)/vdso32.so.dbg: FORCE \ diff --git a/arch/x86/entry/vdso/vclock_gettime.c b/arch/x86/entry/vdso/vclock_gettime.c index fa8dbfcf7ed37f5677d9185d16e9addb114cf83f..9c35dc0a9d64473668abf2870e8ff3ef5d4d0d90 100644 --- a/arch/x86/entry/vdso/vclock_gettime.c +++ b/arch/x86/entry/vdso/vclock_gettime.c @@ -43,8 +43,9 @@ extern u8 hvclock_page notrace static long vdso_fallback_gettime(long clock, struct timespec *ts) { long ret; - asm("syscall" : "=a" (ret) : - "0" (__NR_clock_gettime), "D" (clock), "S" (ts) : "memory"); + asm ("syscall" : "=a" (ret), "=m" (*ts) : + "0" (__NR_clock_gettime), "D" (clock), "S" (ts) : + "memory", "rcx", "r11"); return ret; } @@ -52,8 +53,9 @@ notrace static long vdso_fallback_gtod(struct timeval *tv, struct timezone *tz) { long ret; - asm("syscall" : "=a" (ret) : - "0" (__NR_gettimeofday), "D" (tv), "S" (tz) : "memory"); + asm ("syscall" : "=a" (ret), "=m" (*tv), "=m" (*tz) : + "0" (__NR_gettimeofday), "D" (tv), "S" (tz) : + "memory", "rcx", "r11"); return ret; } @@ -64,13 +66,13 @@ notrace static long vdso_fallback_gettime(long clock, struct timespec *ts) { long ret; - asm( + asm ( "mov %%ebx, %%edx \n" - "mov %2, %%ebx \n" + "mov %[clock], %%ebx \n" "call __kernel_vsyscall \n" "mov %%edx, %%ebx \n" - : "=a" (ret) - : "0" (__NR_clock_gettime), "g" (clock), "c" (ts) + : "=a" (ret), "=m" (*ts) + : "0" (__NR_clock_gettime), [clock] "g" (clock), "c" (ts) : "memory", "edx"); return ret; } @@ -79,13 +81,13 @@ notrace static long vdso_fallback_gtod(struct timeval *tv, struct timezone *tz) { long ret; - asm( + asm ( "mov %%ebx, %%edx \n" - "mov %2, %%ebx \n" + "mov %[tv], %%ebx \n" "call __kernel_vsyscall \n" "mov %%edx, %%ebx \n" - : "=a" (ret) - : "0" (__NR_gettimeofday), "g" (tv), "c" (tz) + : "=a" (ret), "=m" (*tv), "=m" (*tz) + : "0" (__NR_gettimeofday), [tv] "g" (tv), "c" (tz) : "memory", "edx"); return ret; } diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c index 786fd875de9287d8745bb7ec42d52fc7a2a4dac0..8c51844694e2f07f8351b27640a94bad7ab59c76 100644 --- a/arch/x86/events/amd/ibs.c +++ b/arch/x86/events/amd/ibs.c @@ -579,7 +579,7 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs) { struct cpu_perf_ibs *pcpu = this_cpu_ptr(perf_ibs->pcpu); struct perf_event *event = pcpu->event; - struct hw_perf_event *hwc = &event->hw; + struct hw_perf_event *hwc; struct perf_sample_data data; struct perf_raw_record raw; struct pt_regs regs; @@ -602,6 +602,10 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs) return 0; } + if (WARN_ON_ONCE(!event)) + goto fail; + + hwc = &event->hw; msr = hwc->config_base; buf = ibs_data.regs; rdmsrl(msr, *buf); diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 717c9219d00ec3fbdc6ebea65277bfc6025dc8fa..e5097dc85a06cf73d4da6b93aa3f5d34b9bdad6a 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -2462,7 +2462,7 @@ perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs perf_callchain_store(entry, regs->ip); - if (!current->mm) + if (!nmi_uaccess_okay()) return; if (perf_callchain_user32(regs, entry)) diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c index cf372b90557ed4e8a788c8f97b515ac956d2512e..17fbd07e4245bf4737d99592fb06ed4f5e89afd6 100644 --- a/arch/x86/events/intel/lbr.c +++ b/arch/x86/events/intel/lbr.c @@ -346,7 +346,7 @@ static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx) mask = x86_pmu.lbr_nr - 1; tos = task_ctx->tos; - for (i = 0; i < tos; i++) { + for (i = 0; i < task_ctx->valid_lbrs; i++) { lbr_idx = (tos - i) & mask; wrlbr_from(lbr_idx, task_ctx->lbr_from[i]); wrlbr_to (lbr_idx, task_ctx->lbr_to[i]); @@ -354,6 +354,15 @@ static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx) if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO) wrmsrl(MSR_LBR_INFO_0 + lbr_idx, task_ctx->lbr_info[i]); } + + for (; i < x86_pmu.lbr_nr; i++) { + lbr_idx = (tos - i) & mask; + wrlbr_from(lbr_idx, 0); + wrlbr_to(lbr_idx, 0); + if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO) + wrmsrl(MSR_LBR_INFO_0 + lbr_idx, 0); + } + wrmsrl(x86_pmu.lbr_tos, tos); task_ctx->lbr_stack_state = LBR_NONE; } @@ -361,7 +370,7 @@ static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx) static void __intel_pmu_lbr_save(struct x86_perf_task_context *task_ctx) { unsigned lbr_idx, mask; - u64 tos; + u64 tos, from; int i; if (task_ctx->lbr_callstack_users == 0) { @@ -371,13 +380,17 @@ static void __intel_pmu_lbr_save(struct x86_perf_task_context *task_ctx) mask = x86_pmu.lbr_nr - 1; tos = intel_pmu_lbr_tos(); - for (i = 0; i < tos; i++) { + for (i = 0; i < x86_pmu.lbr_nr; i++) { lbr_idx = (tos - i) & mask; - task_ctx->lbr_from[i] = rdlbr_from(lbr_idx); + from = rdlbr_from(lbr_idx); + if (!from) + break; + task_ctx->lbr_from[i] = from; task_ctx->lbr_to[i] = rdlbr_to(lbr_idx); if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO) rdmsrl(MSR_LBR_INFO_0 + lbr_idx, task_ctx->lbr_info[i]); } + task_ctx->valid_lbrs = i; task_ctx->tos = tos; task_ctx->lbr_stack_state = LBR_VALID; } @@ -531,7 +544,7 @@ static void intel_pmu_lbr_read_32(struct cpu_hw_events *cpuc) */ static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc) { - bool need_info = false; + bool need_info = false, call_stack = false; unsigned long mask = x86_pmu.lbr_nr - 1; int lbr_format = x86_pmu.intel_cap.lbr_format; u64 tos = intel_pmu_lbr_tos(); @@ -542,7 +555,7 @@ static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc) if (cpuc->lbr_sel) { need_info = !(cpuc->lbr_sel->config & LBR_NO_INFO); if (cpuc->lbr_sel->config & LBR_CALL_STACK) - num = tos; + call_stack = true; } for (i = 0; i < num; i++) { @@ -555,6 +568,13 @@ static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc) from = rdlbr_from(lbr_idx); to = rdlbr_to(lbr_idx); + /* + * Read LBR call stack entries + * until invalid entry (0s) is detected. + */ + if (call_stack && !from) + break; + if (lbr_format == LBR_FORMAT_INFO && need_info) { u64 info; @@ -1230,4 +1250,8 @@ void intel_pmu_lbr_init_knl(void) x86_pmu.lbr_sel_mask = LBR_SEL_MASK; x86_pmu.lbr_sel_map = snb_lbr_sel_map; + + /* Knights Landing does have MISPREDICT bit */ + if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_LIP) + x86_pmu.intel_cap.lbr_format = LBR_FORMAT_EIP_FLAGS; } diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h index dc4728eccfd86c4a2a97894f53b05b658a6e0155..c6698c63c047b170a17bf508071ba25218565464 100644 --- a/arch/x86/events/perf_event.h +++ b/arch/x86/events/perf_event.h @@ -646,6 +646,7 @@ struct x86_perf_task_context { u64 lbr_to[MAX_LBR_ENTRIES]; u64 lbr_info[MAX_LBR_ENTRIES]; int tos; + int valid_lbrs; int lbr_callstack_users; int lbr_stack_state; }; diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index 5f01671c68f267ccc3b3aedd518134453162733a..a1ed92aae12a6652210e392347cc54bc0b34f29a 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -10,6 +10,7 @@ #include #include #include +#include #define ARCH_APICTIMER_STOPS_ON_C3 1 @@ -613,12 +614,20 @@ extern int default_check_phys_apicid_present(int phys_apicid); #endif #endif /* CONFIG_X86_LOCAL_APIC */ + +#ifdef CONFIG_SMP +bool apic_id_is_primary_thread(unsigned int id); +#else +static inline bool apic_id_is_primary_thread(unsigned int id) { return false; } +#endif + extern void irq_enter(void); extern void irq_exit(void); static inline void entering_irq(void) { irq_enter(); + kvm_set_cpu_l1tf_flush_l1d(); } static inline void entering_ack_irq(void) @@ -631,6 +640,7 @@ static inline void ipi_entering_ack_irq(void) { irq_enter(); ack_APIC_irq(); + kvm_set_cpu_l1tf_flush_l1d(); } static inline void exiting_irq(void) diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index 403e97d5e24322775dc01953ef32f8f4e3dd9276..8418462298e719bf756a9c0745afb24f8f5b21a1 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -219,6 +219,7 @@ #define X86_FEATURE_IBPB ( 7*32+26) /* Indirect Branch Prediction Barrier */ #define X86_FEATURE_STIBP ( 7*32+27) /* Single Thread Indirect Branch Predictors */ #define X86_FEATURE_ZEN ( 7*32+28) /* "" CPU is AMD family 0x17 (Zen) */ +#define X86_FEATURE_L1TF_PTEINV ( 7*32+29) /* "" L1TF workaround PTE inversion */ /* Virtualization flags: Linux defined, word 8 */ #define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ @@ -338,6 +339,7 @@ #define X86_FEATURE_PCONFIG (18*32+18) /* Intel PCONFIG */ #define X86_FEATURE_SPEC_CTRL (18*32+26) /* "" Speculation Control (IBRS + IBPB) */ #define X86_FEATURE_INTEL_STIBP (18*32+27) /* "" Single Thread Indirect Branch Predictors */ +#define X86_FEATURE_FLUSH_L1D (18*32+28) /* Flush L1D cache */ #define X86_FEATURE_ARCH_CAPABILITIES (18*32+29) /* IA32_ARCH_CAPABILITIES MSR (Intel) */ #define X86_FEATURE_SPEC_CTRL_SSBD (18*32+31) /* "" Speculative Store Bypass Disable */ @@ -370,5 +372,6 @@ #define X86_BUG_SPECTRE_V1 X86_BUG(15) /* CPU is affected by Spectre variant 1 attack with conditional branches */ #define X86_BUG_SPECTRE_V2 X86_BUG(16) /* CPU is affected by Spectre variant 2 attack with indirect branches */ #define X86_BUG_SPEC_STORE_BYPASS X86_BUG(17) /* CPU is affected by speculative store bypass attack */ +#define X86_BUG_L1TF X86_BUG(18) /* CPU is affected by L1 Terminal Fault */ #endif /* _ASM_X86_CPUFEATURES_H */ diff --git a/arch/x86/include/asm/dmi.h b/arch/x86/include/asm/dmi.h index 0ab2ab27ad1fb59993fb651f69f49df50e857ff9..b825cb201251654f7a085b0b612a0b574979fa2b 100644 --- a/arch/x86/include/asm/dmi.h +++ b/arch/x86/include/asm/dmi.h @@ -4,8 +4,8 @@ #include #include +#include -#include #include static __always_inline __init void *dmi_alloc(unsigned len) diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h index e203169931c721b7958c940694458c11a270b982..6390bd8c141b44cd988dd21bc4b5b3efbbf1688b 100644 --- a/arch/x86/include/asm/fixmap.h +++ b/arch/x86/include/asm/fixmap.h @@ -14,6 +14,16 @@ #ifndef _ASM_X86_FIXMAP_H #define _ASM_X86_FIXMAP_H +/* + * Exposed to assembly code for setting up initial page tables. Cannot be + * calculated in assembly code (fixmap entries are an enum), but is sanity + * checked in the actual fixmap C code to make sure that the fixmap is + * covered fully. + */ +#define FIXMAP_PMD_NUM 2 +/* fixmap starts downwards from the 507th entry in level2_fixmap_pgt */ +#define FIXMAP_PMD_TOP 507 + #ifndef __ASSEMBLY__ #include #include diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h index 51cc979dd3642ff4ad743ba4efcd38c97a6877b9..486c843273c46fe6c102fdce5997d8d9ed211a80 100644 --- a/arch/x86/include/asm/hardirq.h +++ b/arch/x86/include/asm/hardirq.h @@ -3,10 +3,12 @@ #define _ASM_X86_HARDIRQ_H #include -#include typedef struct { - unsigned int __softirq_pending; + u16 __softirq_pending; +#if IS_ENABLED(CONFIG_KVM_INTEL) + u8 kvm_cpu_l1tf_flush_l1d; +#endif unsigned int __nmi_count; /* arch dependent */ #ifdef CONFIG_X86_LOCAL_APIC unsigned int apic_timer_irqs; /* arch dependent */ @@ -62,4 +64,24 @@ extern u64 arch_irq_stat_cpu(unsigned int cpu); extern u64 arch_irq_stat(void); #define arch_irq_stat arch_irq_stat + +#if IS_ENABLED(CONFIG_KVM_INTEL) +static inline void kvm_set_cpu_l1tf_flush_l1d(void) +{ + __this_cpu_write(irq_stat.kvm_cpu_l1tf_flush_l1d, 1); +} + +static inline void kvm_clear_cpu_l1tf_flush_l1d(void) +{ + __this_cpu_write(irq_stat.kvm_cpu_l1tf_flush_l1d, 0); +} + +static inline bool kvm_get_cpu_l1tf_flush_l1d(void) +{ + return __this_cpu_read(irq_stat.kvm_cpu_l1tf_flush_l1d); +} +#else /* !IS_ENABLED(CONFIG_KVM_INTEL) */ +static inline void kvm_set_cpu_l1tf_flush_l1d(void) { } +#endif /* IS_ENABLED(CONFIG_KVM_INTEL) */ + #endif /* _ASM_X86_HARDIRQ_H */ diff --git a/arch/x86/include/asm/i8259.h b/arch/x86/include/asm/i8259.h index 5cdcdbd4d892029f7cbd90ab30dfe0832e5780f4..89789e8c80f66a97db08ffad891ed26e5025219e 100644 --- a/arch/x86/include/asm/i8259.h +++ b/arch/x86/include/asm/i8259.h @@ -3,6 +3,7 @@ #define _ASM_X86_I8259_H #include +#include extern unsigned int cached_irq_mask; diff --git a/arch/x86/include/asm/irqflags.h b/arch/x86/include/asm/irqflags.h index c4fc17220df959f2d5feb493af6374e7dacce613..15450a675031d3562b4a9da3d3b15816c11003fb 100644 --- a/arch/x86/include/asm/irqflags.h +++ b/arch/x86/include/asm/irqflags.h @@ -13,6 +13,8 @@ * Interrupt control: */ +/* Declaration required for gcc < 4.9 to prevent -Werror=missing-prototypes */ +extern inline unsigned long native_save_fl(void); extern inline unsigned long native_save_fl(void) { unsigned long flags; @@ -31,7 +33,8 @@ extern inline unsigned long native_save_fl(void) return flags; } -static inline void native_restore_fl(unsigned long flags) +extern inline void native_restore_fl(unsigned long flags); +extern inline void native_restore_fl(unsigned long flags) { asm volatile("push %0 ; popf" : /* no output */ diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 174b9c41efce00d67d034616afcc974a7e51fe2f..4015b88383ce98ad5cbc828f098bb0d3b8b16598 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -506,6 +507,7 @@ struct kvm_vcpu_arch { u64 smbase; bool tpr_access_reporting; u64 ia32_xss; + u64 microcode_version; /* * Paging state of the vcpu @@ -693,6 +695,9 @@ struct kvm_vcpu_arch { /* be preempted when it's in kernel-mode(cpl=0) */ bool preempted_in_kernel; + + /* Flush the L1 Data cache for L1TF mitigation on VMENTER */ + bool l1tf_flush_l1d; }; struct kvm_lpage_info { @@ -862,6 +867,7 @@ struct kvm_vcpu_stat { u64 signal_exits; u64 irq_window_exits; u64 nmi_window_exits; + u64 l1d_flush; u64 halt_exits; u64 halt_successful_poll; u64 halt_attempted_poll; @@ -1061,6 +1067,8 @@ struct kvm_x86_ops { void (*cancel_hv_timer)(struct kvm_vcpu *vcpu); void (*setup_mce)(struct kvm_vcpu *vcpu); + + int (*get_msr_feature)(struct kvm_msr_entry *entry); }; struct kvm_arch_async_pf { @@ -1366,6 +1374,7 @@ int kvm_cpu_get_interrupt(struct kvm_vcpu *v); void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event); void kvm_vcpu_reload_apic_access_page(struct kvm_vcpu *vcpu); +u64 kvm_get_arch_capabilities(void); void kvm_define_shared_msr(unsigned index, u32 msr); int kvm_set_shared_msr(unsigned index, u64 val, u64 mask); diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index 340070415c2c3a93b0305ed7624ceaa62bd4362f..90fef69e4c5a1e327e0aee654d0240f70a562ca9 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h @@ -200,6 +200,7 @@ enum mce_notifier_prios { MCE_PRIO_LOWEST = 0, }; +struct notifier_block; extern void mce_register_decode_chain(struct notifier_block *nb); extern void mce_unregister_decode_chain(struct notifier_block *nb); diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 504b21692d3277d37ee1d22bf1367faec9d4db97..ef7eec669a1bcc5d1ff80a50920b4e74ba137e3b 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -70,12 +70,19 @@ #define MSR_IA32_ARCH_CAPABILITIES 0x0000010a #define ARCH_CAP_RDCL_NO (1 << 0) /* Not susceptible to Meltdown */ #define ARCH_CAP_IBRS_ALL (1 << 1) /* Enhanced IBRS support */ +#define ARCH_CAP_SKIP_VMENTRY_L1DFLUSH (1 << 3) /* Skip L1D flush on vmentry */ #define ARCH_CAP_SSB_NO (1 << 4) /* * Not susceptible to Speculative Store Bypass * attack, so no Speculative Store Bypass * control required. */ +#define MSR_IA32_FLUSH_CMD 0x0000010b +#define L1D_FLUSH (1 << 0) /* + * Writeback and invalidate the + * L1 data cache. + */ + #define MSR_IA32_BBL_CR_CTL 0x00000119 #define MSR_IA32_BBL_CR_CTL3 0x0000011e diff --git a/arch/x86/include/asm/page_32_types.h b/arch/x86/include/asm/page_32_types.h index aa30c3241ea7da812da88c4f4151c9139db2845f..0d5c739eebd715f387d37a81a52b837119daf9ad 100644 --- a/arch/x86/include/asm/page_32_types.h +++ b/arch/x86/include/asm/page_32_types.h @@ -29,8 +29,13 @@ #define N_EXCEPTION_STACKS 1 #ifdef CONFIG_X86_PAE -/* 44=32+12, the limit we can fit into an unsigned long pfn */ -#define __PHYSICAL_MASK_SHIFT 44 +/* + * This is beyond the 44 bit limit imposed by the 32bit long pfns, + * but we need the full mask to make sure inverted PROT_NONE + * entries have all the host bits set in a guest. + * The real limit is still 44 bits. + */ +#define __PHYSICAL_MASK_SHIFT 52 #define __VIRTUAL_MASK_SHIFT 32 #else /* !CONFIG_X86_PAE */ diff --git a/arch/x86/include/asm/pgtable-2level.h b/arch/x86/include/asm/pgtable-2level.h index 685ffe8a0eaf84d5a3b0374cf7ef31cb3e51bb7c..60d0f90153178b3fb104360536854d676f7429ee 100644 --- a/arch/x86/include/asm/pgtable-2level.h +++ b/arch/x86/include/asm/pgtable-2level.h @@ -95,4 +95,21 @@ static inline unsigned long pte_bitop(unsigned long value, unsigned int rightshi #define __pte_to_swp_entry(pte) ((swp_entry_t) { (pte).pte_low }) #define __swp_entry_to_pte(x) ((pte_t) { .pte = (x).val }) +/* No inverted PFNs on 2 level page tables */ + +static inline u64 protnone_mask(u64 val) +{ + return 0; +} + +static inline u64 flip_protnone_guard(u64 oldval, u64 val, u64 mask) +{ + return val; +} + +static inline bool __pte_needs_invert(u64 val) +{ + return false; +} + #endif /* _ASM_X86_PGTABLE_2LEVEL_H */ diff --git a/arch/x86/include/asm/pgtable-3level.h b/arch/x86/include/asm/pgtable-3level.h index bc4af5453802559af4c1f14a2e3a3dbaf96e57dc..c5d4931d1ef9b97088dd13e5cf3fbd8a3ab12f5f 100644 --- a/arch/x86/include/asm/pgtable-3level.h +++ b/arch/x86/include/asm/pgtable-3level.h @@ -2,6 +2,8 @@ #ifndef _ASM_X86_PGTABLE_3LEVEL_H #define _ASM_X86_PGTABLE_3LEVEL_H +#include + /* * Intel Physical Address Extension (PAE) Mode - three-level page * tables on PPro+ CPUs. @@ -147,10 +149,7 @@ static inline pte_t native_ptep_get_and_clear(pte_t *ptep) { pte_t res; - /* xchg acts as a barrier before the setting of the high bits */ - res.pte_low = xchg(&ptep->pte_low, 0); - res.pte_high = ptep->pte_high; - ptep->pte_high = 0; + res.pte = (pteval_t)atomic64_xchg((atomic64_t *)ptep, 0); return res; } @@ -206,12 +205,43 @@ static inline pud_t native_pudp_get_and_clear(pud_t *pudp) #endif /* Encode and de-code a swap entry */ +#define SWP_TYPE_BITS 5 + +#define SWP_OFFSET_FIRST_BIT (_PAGE_BIT_PROTNONE + 1) + +/* We always extract/encode the offset by shifting it all the way up, and then down again */ +#define SWP_OFFSET_SHIFT (SWP_OFFSET_FIRST_BIT + SWP_TYPE_BITS) + #define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > 5) #define __swp_type(x) (((x).val) & 0x1f) #define __swp_offset(x) ((x).val >> 5) #define __swp_entry(type, offset) ((swp_entry_t){(type) | (offset) << 5}) -#define __pte_to_swp_entry(pte) ((swp_entry_t){ (pte).pte_high }) -#define __swp_entry_to_pte(x) ((pte_t){ { .pte_high = (x).val } }) + +/* + * Normally, __swp_entry() converts from arch-independent swp_entry_t to + * arch-dependent swp_entry_t, and __swp_entry_to_pte() just stores the result + * to pte. But here we have 32bit swp_entry_t and 64bit pte, and need to use the + * whole 64 bits. Thus, we shift the "real" arch-dependent conversion to + * __swp_entry_to_pte() through the following helper macro based on 64bit + * __swp_entry(). + */ +#define __swp_pteval_entry(type, offset) ((pteval_t) { \ + (~(pteval_t)(offset) << SWP_OFFSET_SHIFT >> SWP_TYPE_BITS) \ + | ((pteval_t)(type) << (64 - SWP_TYPE_BITS)) }) + +#define __swp_entry_to_pte(x) ((pte_t){ .pte = \ + __swp_pteval_entry(__swp_type(x), __swp_offset(x)) }) +/* + * Analogically, __pte_to_swp_entry() doesn't just extract the arch-dependent + * swp_entry_t, but also has to convert it from 64bit to the 32bit + * intermediate representation, using the following macros based on 64bit + * __swp_type() and __swp_offset(). + */ +#define __pteval_swp_type(x) ((unsigned long)((x).pte >> (64 - SWP_TYPE_BITS))) +#define __pteval_swp_offset(x) ((unsigned long)(~((x).pte) << SWP_TYPE_BITS >> SWP_OFFSET_SHIFT)) + +#define __pte_to_swp_entry(pte) (__swp_entry(__pteval_swp_type(pte), \ + __pteval_swp_offset(pte))) #define gup_get_pte gup_get_pte /* @@ -260,4 +290,6 @@ static inline pte_t gup_get_pte(pte_t *ptep) return pte; } +#include + #endif /* _ASM_X86_PGTABLE_3LEVEL_H */ diff --git a/arch/x86/include/asm/pgtable-invert.h b/arch/x86/include/asm/pgtable-invert.h new file mode 100644 index 0000000000000000000000000000000000000000..a0c1525f1b6f417448bebb5898a48b71f5b86c0d --- /dev/null +++ b/arch/x86/include/asm/pgtable-invert.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_PGTABLE_INVERT_H +#define _ASM_PGTABLE_INVERT_H 1 + +#ifndef __ASSEMBLY__ + +/* + * A clear pte value is special, and doesn't get inverted. + * + * Note that even users that only pass a pgprot_t (rather + * than a full pte) won't trigger the special zero case, + * because even PAGE_NONE has _PAGE_PROTNONE | _PAGE_ACCESSED + * set. So the all zero case really is limited to just the + * cleared page table entry case. + */ +static inline bool __pte_needs_invert(u64 val) +{ + return val && !(val & _PAGE_PRESENT); +} + +/* Get a mask to xor with the page table entry to get the correct pfn. */ +static inline u64 protnone_mask(u64 val) +{ + return __pte_needs_invert(val) ? ~0ull : 0; +} + +static inline u64 flip_protnone_guard(u64 oldval, u64 val, u64 mask) +{ + /* + * When a PTE transitions from NONE to !NONE or vice-versa + * invert the PFN part to stop speculation. + * pte_pfn undoes this when needed. + */ + if (__pte_needs_invert(oldval) != __pte_needs_invert(val)) + val = (val & ~mask) | (~val & mask); + return val; +} + +#endif /* __ASSEMBLY__ */ + +#endif diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index 5c790e93657d7615e2f28809a28d898248372a84..6a4b1a54ff479cf2ff018470351de45890625582 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -185,19 +185,29 @@ static inline int pte_special(pte_t pte) return pte_flags(pte) & _PAGE_SPECIAL; } +/* Entries that were set to PROT_NONE are inverted */ + +static inline u64 protnone_mask(u64 val); + static inline unsigned long pte_pfn(pte_t pte) { - return (pte_val(pte) & PTE_PFN_MASK) >> PAGE_SHIFT; + phys_addr_t pfn = pte_val(pte); + pfn ^= protnone_mask(pfn); + return (pfn & PTE_PFN_MASK) >> PAGE_SHIFT; } static inline unsigned long pmd_pfn(pmd_t pmd) { - return (pmd_val(pmd) & pmd_pfn_mask(pmd)) >> PAGE_SHIFT; + phys_addr_t pfn = pmd_val(pmd); + pfn ^= protnone_mask(pfn); + return (pfn & pmd_pfn_mask(pmd)) >> PAGE_SHIFT; } static inline unsigned long pud_pfn(pud_t pud) { - return (pud_val(pud) & pud_pfn_mask(pud)) >> PAGE_SHIFT; + phys_addr_t pfn = pud_val(pud); + pfn ^= protnone_mask(pfn); + return (pfn & pud_pfn_mask(pud)) >> PAGE_SHIFT; } static inline unsigned long p4d_pfn(p4d_t p4d) @@ -400,11 +410,6 @@ static inline pmd_t pmd_mkwrite(pmd_t pmd) return pmd_set_flags(pmd, _PAGE_RW); } -static inline pmd_t pmd_mknotpresent(pmd_t pmd) -{ - return pmd_clear_flags(pmd, _PAGE_PRESENT | _PAGE_PROTNONE); -} - static inline pud_t pud_set_flags(pud_t pud, pudval_t set) { pudval_t v = native_pud_val(pud); @@ -459,11 +464,6 @@ static inline pud_t pud_mkwrite(pud_t pud) return pud_set_flags(pud, _PAGE_RW); } -static inline pud_t pud_mknotpresent(pud_t pud) -{ - return pud_clear_flags(pud, _PAGE_PRESENT | _PAGE_PROTNONE); -} - #ifdef CONFIG_HAVE_ARCH_SOFT_DIRTY static inline int pte_soft_dirty(pte_t pte) { @@ -528,25 +528,45 @@ static inline pgprotval_t massage_pgprot(pgprot_t pgprot) static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot) { - return __pte(((phys_addr_t)page_nr << PAGE_SHIFT) | - massage_pgprot(pgprot)); + phys_addr_t pfn = (phys_addr_t)page_nr << PAGE_SHIFT; + pfn ^= protnone_mask(pgprot_val(pgprot)); + pfn &= PTE_PFN_MASK; + return __pte(pfn | massage_pgprot(pgprot)); } static inline pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot) { - return __pmd(((phys_addr_t)page_nr << PAGE_SHIFT) | - massage_pgprot(pgprot)); + phys_addr_t pfn = (phys_addr_t)page_nr << PAGE_SHIFT; + pfn ^= protnone_mask(pgprot_val(pgprot)); + pfn &= PHYSICAL_PMD_PAGE_MASK; + return __pmd(pfn | massage_pgprot(pgprot)); } static inline pud_t pfn_pud(unsigned long page_nr, pgprot_t pgprot) { - return __pud(((phys_addr_t)page_nr << PAGE_SHIFT) | - massage_pgprot(pgprot)); + phys_addr_t pfn = (phys_addr_t)page_nr << PAGE_SHIFT; + pfn ^= protnone_mask(pgprot_val(pgprot)); + pfn &= PHYSICAL_PUD_PAGE_MASK; + return __pud(pfn | massage_pgprot(pgprot)); } +static inline pmd_t pmd_mknotpresent(pmd_t pmd) +{ + return pfn_pmd(pmd_pfn(pmd), + __pgprot(pmd_flags(pmd) & ~(_PAGE_PRESENT|_PAGE_PROTNONE))); +} + +static inline pud_t pud_mknotpresent(pud_t pud) +{ + return pfn_pud(pud_pfn(pud), + __pgprot(pud_flags(pud) & ~(_PAGE_PRESENT|_PAGE_PROTNONE))); +} + +static inline u64 flip_protnone_guard(u64 oldval, u64 val, u64 mask); + static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { - pteval_t val = pte_val(pte); + pteval_t val = pte_val(pte), oldval = val; /* * Chop off the NX bit (if present), and add the NX portion of @@ -554,17 +574,17 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) */ val &= _PAGE_CHG_MASK; val |= massage_pgprot(newprot) & ~_PAGE_CHG_MASK; - + val = flip_protnone_guard(oldval, val, PTE_PFN_MASK); return __pte(val); } static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) { - pmdval_t val = pmd_val(pmd); + pmdval_t val = pmd_val(pmd), oldval = val; val &= _HPAGE_CHG_MASK; val |= massage_pgprot(newprot) & ~_HPAGE_CHG_MASK; - + val = flip_protnone_guard(oldval, val, PHYSICAL_PMD_PAGE_MASK); return __pmd(val); } @@ -1274,6 +1294,14 @@ static inline bool pud_access_permitted(pud_t pud, bool write) return __pte_access_permitted(pud_val(pud), write); } +#define __HAVE_ARCH_PFN_MODIFY_ALLOWED 1 +extern bool pfn_modify_allowed(unsigned long pfn, pgprot_t prot); + +static inline bool arch_has_pfn_modify_check(void) +{ + return boot_cpu_has_bug(X86_BUG_L1TF); +} + #include #endif /* __ASSEMBLY__ */ diff --git a/arch/x86/include/asm/pgtable_64.h b/arch/x86/include/asm/pgtable_64.h index 1149d2112b2e17347e8f85c4cae355f4522cc40a..ef938583147ea4d7775c23427f8b13e77ae1a21a 100644 --- a/arch/x86/include/asm/pgtable_64.h +++ b/arch/x86/include/asm/pgtable_64.h @@ -14,6 +14,7 @@ #include #include #include +#include extern p4d_t level4_kernel_pgt[512]; extern p4d_t level4_ident_pgt[512]; @@ -22,7 +23,7 @@ extern pud_t level3_ident_pgt[512]; extern pmd_t level2_kernel_pgt[512]; extern pmd_t level2_fixmap_pgt[512]; extern pmd_t level2_ident_pgt[512]; -extern pte_t level1_fixmap_pgt[512]; +extern pte_t level1_fixmap_pgt[512 * FIXMAP_PMD_NUM]; extern pgd_t init_top_pgt[]; #define swapper_pg_dir init_top_pgt @@ -276,7 +277,7 @@ static inline int pgd_large(pgd_t pgd) { return 0; } * * | ... | 11| 10| 9|8|7|6|5| 4| 3|2| 1|0| <- bit number * | ... |SW3|SW2|SW1|G|L|D|A|CD|WT|U| W|P| <- bit names - * | OFFSET (14->63) | TYPE (9-13) |0|0|X|X| X| X|X|SD|0| <- swp entry + * | TYPE (59-63) | ~OFFSET (9-58) |0|0|X|X| X| X|X|SD|0| <- swp entry * * G (8) is aliased and used as a PROT_NONE indicator for * !present ptes. We need to start storing swap entries above @@ -289,20 +290,34 @@ static inline int pgd_large(pgd_t pgd) { return 0; } * * Bit 7 in swp entry should be 0 because pmd_present checks not only P, * but also L and G. + * + * The offset is inverted by a binary not operation to make the high + * physical bits set. */ -#define SWP_TYPE_FIRST_BIT (_PAGE_BIT_PROTNONE + 1) -#define SWP_TYPE_BITS 5 -/* Place the offset above the type: */ -#define SWP_OFFSET_FIRST_BIT (SWP_TYPE_FIRST_BIT + SWP_TYPE_BITS) +#define SWP_TYPE_BITS 5 + +#define SWP_OFFSET_FIRST_BIT (_PAGE_BIT_PROTNONE + 1) + +/* We always extract/encode the offset by shifting it all the way up, and then down again */ +#define SWP_OFFSET_SHIFT (SWP_OFFSET_FIRST_BIT+SWP_TYPE_BITS) #define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > SWP_TYPE_BITS) -#define __swp_type(x) (((x).val >> (SWP_TYPE_FIRST_BIT)) \ - & ((1U << SWP_TYPE_BITS) - 1)) -#define __swp_offset(x) ((x).val >> SWP_OFFSET_FIRST_BIT) -#define __swp_entry(type, offset) ((swp_entry_t) { \ - ((type) << (SWP_TYPE_FIRST_BIT)) \ - | ((offset) << SWP_OFFSET_FIRST_BIT) }) +/* Extract the high bits for type */ +#define __swp_type(x) ((x).val >> (64 - SWP_TYPE_BITS)) + +/* Shift up (to get rid of type), then down to get value */ +#define __swp_offset(x) (~(x).val << SWP_TYPE_BITS >> SWP_OFFSET_SHIFT) + +/* + * Shift the offset up "too far" by TYPE bits, then down again + * The offset is inverted by a binary not operation to make the high + * physical bits set. + */ +#define __swp_entry(type, offset) ((swp_entry_t) { \ + (~(unsigned long)(offset) << SWP_OFFSET_SHIFT >> SWP_TYPE_BITS) \ + | ((unsigned long)(type) << (64-SWP_TYPE_BITS)) }) + #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val((pte)) }) #define __pmd_to_swp_entry(pmd) ((swp_entry_t) { pmd_val((pmd)) }) #define __swp_entry_to_pte(x) ((pte_t) { .pte = (x).val }) @@ -346,5 +361,7 @@ static inline bool gup_fast_permitted(unsigned long start, int nr_pages, return true; } +#include + #endif /* !__ASSEMBLY__ */ #endif /* _ASM_X86_PGTABLE_64_H */ diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 3222c7746cb1f857b686dbbdf5d06c475cf6aaad..b12c8d70dd33d0044c60f2c324717d62d631e086 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -132,6 +132,8 @@ struct cpuinfo_x86 { /* Index into per_cpu list: */ u16 cpu_index; u32 microcode; + /* Address space bits used by the cache internally */ + u8 x86_cache_bits; } __randomize_layout; struct cpuid_regs { @@ -180,6 +182,11 @@ extern const struct seq_operations cpuinfo_op; extern void cpu_detect(struct cpuinfo_x86 *c); +static inline unsigned long long l1tf_pfn_limit(void) +{ + return BIT_ULL(boot_cpu_data.x86_cache_bits - 1 - PAGE_SHIFT); +} + extern void early_cpu_init(void); extern void identify_boot_cpu(void); extern void identify_secondary_cpu(struct cpuinfo_x86 *); @@ -969,4 +976,16 @@ bool xen_set_default_idle(void); void stop_this_cpu(void *dummy); void df_debug(struct pt_regs *regs, long error_code); void microcode_check(void); + +enum l1tf_mitigations { + L1TF_MITIGATION_OFF, + L1TF_MITIGATION_FLUSH_NOWARN, + L1TF_MITIGATION_FLUSH, + L1TF_MITIGATION_FLUSH_NOSMT, + L1TF_MITIGATION_FULL, + L1TF_MITIGATION_FULL_FORCE +}; + +extern enum l1tf_mitigations l1tf_mitigation; + #endif /* _ASM_X86_PROCESSOR_H */ diff --git a/arch/x86/include/asm/smp.h b/arch/x86/include/asm/smp.h index 461f53d27708ae8b80622753122c1a4927537ee2..fe2ee61880a86a7da9d2e33a1604c58d7051b86a 100644 --- a/arch/x86/include/asm/smp.h +++ b/arch/x86/include/asm/smp.h @@ -170,7 +170,6 @@ static inline int wbinvd_on_all_cpus(void) wbinvd(); return 0; } -#define smp_num_siblings 1 #endif /* CONFIG_SMP */ extern unsigned disabled_cpus; diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h index 875ca99b82eef003781464af111214392fdd0f5c..5f00ecb9d2515e693218d0e4a561824fe0279d94 100644 --- a/arch/x86/include/asm/tlbflush.h +++ b/arch/x86/include/asm/tlbflush.h @@ -175,8 +175,16 @@ struct tlb_state { * are on. This means that it may not match current->active_mm, * which will contain the previous user mm when we're in lazy TLB * mode even if we've already switched back to swapper_pg_dir. + * + * During switch_mm_irqs_off(), loaded_mm will be set to + * LOADED_MM_SWITCHING during the brief interrupts-off window + * when CR3 and loaded_mm would otherwise be inconsistent. This + * is for nmi_uaccess_okay()'s benefit. */ struct mm_struct *loaded_mm; + +#define LOADED_MM_SWITCHING ((struct mm_struct *)1) + u16 loaded_mm_asid; u16 next_asid; /* last user mm's ctx id */ @@ -246,6 +254,38 @@ struct tlb_state { }; DECLARE_PER_CPU_SHARED_ALIGNED(struct tlb_state, cpu_tlbstate); +/* + * Blindly accessing user memory from NMI context can be dangerous + * if we're in the middle of switching the current user task or + * switching the loaded mm. It can also be dangerous if we + * interrupted some kernel code that was temporarily using a + * different mm. + */ +static inline bool nmi_uaccess_okay(void) +{ + struct mm_struct *loaded_mm = this_cpu_read(cpu_tlbstate.loaded_mm); + struct mm_struct *current_mm = current->mm; + + VM_WARN_ON_ONCE(!loaded_mm); + + /* + * The condition we want to check is + * current_mm->pgd == __va(read_cr3_pa()). This may be slow, though, + * if we're running in a VM with shadow paging, and nmi_uaccess_okay() + * is supposed to be reasonably fast. + * + * Instead, we check the almost equivalent but somewhat conservative + * condition below, and we rely on the fact that switch_mm_irqs_off() + * sets loaded_mm to LOADED_MM_SWITCHING before writing to CR3. + */ + if (loaded_mm != current_mm) + return false; + + VM_WARN_ON_ONCE(current_mm->pgd != __va(read_cr3_pa())); + + return true; +} + /* Initialize cr4 shadow for this CPU. */ static inline void cr4_init_shadow(void) { diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h index c1d2a9892352742a1512306138da023d77c6050b..453cf38a1c33d5b2452dff29be06ce52b5b30ffb 100644 --- a/arch/x86/include/asm/topology.h +++ b/arch/x86/include/asm/topology.h @@ -123,13 +123,17 @@ static inline int topology_max_smt_threads(void) } int topology_update_package_map(unsigned int apicid, unsigned int cpu); -extern int topology_phys_to_logical_pkg(unsigned int pkg); +int topology_phys_to_logical_pkg(unsigned int pkg); +bool topology_is_primary_thread(unsigned int cpu); +bool topology_smt_supported(void); #else #define topology_max_packages() (1) static inline int topology_update_package_map(unsigned int apicid, unsigned int cpu) { return 0; } static inline int topology_phys_to_logical_pkg(unsigned int pkg) { return 0; } static inline int topology_max_smt_threads(void) { return 1; } +static inline bool topology_is_primary_thread(unsigned int cpu) { return true; } +static inline bool topology_smt_supported(void) { return false; } #endif static inline void arch_fix_phys_package_id(int num, u32 slot) diff --git a/arch/x86/include/asm/vgtod.h b/arch/x86/include/asm/vgtod.h index 52250681f68c7410b30f42d9e424553aaed4f313..d92ccff4e615d5a868e5dd4e69834db1cf73420e 100644 --- a/arch/x86/include/asm/vgtod.h +++ b/arch/x86/include/asm/vgtod.h @@ -93,7 +93,7 @@ static inline unsigned int __getcpu(void) * * If RDPID is available, use it. */ - alternative_io ("lsl %[p],%[seg]", + alternative_io ("lsl %[seg],%[p]", ".byte 0xf3,0x0f,0xc7,0xf8", /* RDPID %eax/rax */ X86_FEATURE_RDPID, [p] "=a" (p), [seg] "r" (__PER_CPU_SEG)); diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h index 7c300299e12eaf862e48715e4bd6e23cd42574da..08c14aec26acaecb7ed96f04cd87da8a0d123116 100644 --- a/arch/x86/include/asm/vmx.h +++ b/arch/x86/include/asm/vmx.h @@ -571,4 +571,15 @@ enum vm_instruction_error_number { VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID = 28, }; +enum vmx_l1d_flush_state { + VMENTER_L1D_FLUSH_AUTO, + VMENTER_L1D_FLUSH_NEVER, + VMENTER_L1D_FLUSH_COND, + VMENTER_L1D_FLUSH_ALWAYS, + VMENTER_L1D_FLUSH_EPT_DISABLED, + VMENTER_L1D_FLUSH_NOT_REQUIRED, +}; + +extern enum vmx_l1d_flush_state l1tf_vmx_mitigation; + #endif diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index f48a51335538813cdd96ba82a46e87e745d9ef3f..2e64178f284da29666a9f4108c3f5614377575b1 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -56,6 +57,7 @@ #include #include #include +#include unsigned int num_processors; @@ -2092,6 +2094,23 @@ static int cpuid_to_apicid[] = { [0 ... NR_CPUS - 1] = -1, }; +#ifdef CONFIG_SMP +/** + * apic_id_is_primary_thread - Check whether APIC ID belongs to a primary thread + * @id: APIC ID to check + */ +bool apic_id_is_primary_thread(unsigned int apicid) +{ + u32 mask; + + if (smp_num_siblings == 1) + return true; + /* Isolate the SMT bit(s) in the APICID and check for 0 */ + mask = (1U << (fls(smp_num_siblings) - 1)) - 1; + return !(apicid & mask); +} +#endif + /* * Should use this API to allocate logical CPU IDs to keep nr_logical_cpuids * and cpuid_to_apicid[] synchronized. diff --git a/arch/x86/kernel/apic/htirq.c b/arch/x86/kernel/apic/htirq.c index 56ccf9346b08ac4bf3e54e7994074b6c04fb02e8..741de281ed5de06f917c14e6943fc383a0003bda 100644 --- a/arch/x86/kernel/apic/htirq.c +++ b/arch/x86/kernel/apic/htirq.c @@ -16,6 +16,8 @@ #include #include #include +#include + #include #include #include diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 3b89b27945fffc8f7c9d8dd28f9ed787158ad833..96a8a68f9c793377c305edf63113cd69c352cf45 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -33,6 +33,7 @@ #include #include +#include #include #include #include diff --git a/arch/x86/kernel/apic/msi.c b/arch/x86/kernel/apic/msi.c index 9b18be76442236eab971cab86cbf366f9e1e134f..f10e7f93b0e2c04e7b5f22adbc7ebb574f710281 100644 --- a/arch/x86/kernel/apic/msi.c +++ b/arch/x86/kernel/apic/msi.c @@ -12,6 +12,7 @@ */ #include #include +#include #include #include #include diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c index 2ce1c708b8ee399db1f856ef8ce8d50cdec66bfb..b958082c74a77f0903c830949f6b3aae667adea9 100644 --- a/arch/x86/kernel/apic/vector.c +++ b/arch/x86/kernel/apic/vector.c @@ -11,6 +11,7 @@ * published by the Free Software Foundation. */ #include +#include #include #include #include diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index 90574f731c05062bea029310560f853489575ee5..dda741bd57892037ebcd19bb106109399847d4be 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -298,7 +298,6 @@ static int nearby_node(int apicid) } #endif -#ifdef CONFIG_SMP /* * Fix up cpu_core_id for pre-F17h systems to be in the * [0 .. cores_per_node - 1] range. Not really needed but @@ -315,6 +314,13 @@ static void legacy_fixup_core_id(struct cpuinfo_x86 *c) c->cpu_core_id %= cus_per_node; } + +static void amd_get_topology_early(struct cpuinfo_x86 *c) +{ + if (cpu_has(c, X86_FEATURE_TOPOEXT)) + smp_num_siblings = ((cpuid_ebx(0x8000001e) >> 8) & 0xff) + 1; +} + /* * Fixup core topology information for * (1) AMD multi-node processors @@ -333,7 +339,6 @@ static void amd_get_topology(struct cpuinfo_x86 *c) cpuid(0x8000001e, &eax, &ebx, &ecx, &edx); node_id = ecx & 0xff; - smp_num_siblings = ((ebx >> 8) & 0xff) + 1; if (c->x86 == 0x15) c->cu_id = ebx & 0xff; @@ -376,7 +381,6 @@ static void amd_get_topology(struct cpuinfo_x86 *c) legacy_fixup_core_id(c); } } -#endif /* * On a AMD dual core setup the lower bits of the APIC id distinguish the cores. @@ -384,7 +388,6 @@ static void amd_get_topology(struct cpuinfo_x86 *c) */ static void amd_detect_cmp(struct cpuinfo_x86 *c) { -#ifdef CONFIG_SMP unsigned bits; int cpu = smp_processor_id(); @@ -396,16 +399,11 @@ static void amd_detect_cmp(struct cpuinfo_x86 *c) /* use socket ID also for last level cache */ per_cpu(cpu_llc_id, cpu) = c->phys_proc_id; amd_get_topology(c); -#endif } u16 amd_get_nb_id(int cpu) { - u16 id = 0; -#ifdef CONFIG_SMP - id = per_cpu(cpu_llc_id, cpu); -#endif - return id; + return per_cpu(cpu_llc_id, cpu); } EXPORT_SYMBOL_GPL(amd_get_nb_id); @@ -579,6 +577,7 @@ static void bsp_init_amd(struct cpuinfo_x86 *c) static void early_init_amd(struct cpuinfo_x86 *c) { + u64 value; u32 dummy; early_init_amd_mc(c); @@ -668,6 +667,22 @@ static void early_init_amd(struct cpuinfo_x86 *c) clear_cpu_cap(c, X86_FEATURE_SME); } } + + /* Re-enable TopologyExtensions if switched off by BIOS */ + if (c->x86 == 0x15 && + (c->x86_model >= 0x10 && c->x86_model <= 0x6f) && + !cpu_has(c, X86_FEATURE_TOPOEXT)) { + + if (msr_set_bit(0xc0011005, 54) > 0) { + rdmsrl(0xc0011005, value); + if (value & BIT_64(54)) { + set_cpu_cap(c, X86_FEATURE_TOPOEXT); + pr_info_once(FW_INFO "CPU: Re-enabling disabled Topology Extensions Support.\n"); + } + } + } + + amd_get_topology_early(c); } static void init_amd_k8(struct cpuinfo_x86 *c) @@ -759,19 +774,6 @@ static void init_amd_bd(struct cpuinfo_x86 *c) { u64 value; - /* re-enable TopologyExtensions if switched off by BIOS */ - if ((c->x86_model >= 0x10) && (c->x86_model <= 0x6f) && - !cpu_has(c, X86_FEATURE_TOPOEXT)) { - - if (msr_set_bit(0xc0011005, 54) > 0) { - rdmsrl(0xc0011005, value); - if (value & BIT_64(54)) { - set_cpu_cap(c, X86_FEATURE_TOPOEXT); - pr_info_once(FW_INFO "CPU: Re-enabling disabled Topology Extensions Support.\n"); - } - } - } - /* * The way access filter has a performance penalty on some workloads. * Disable it on the affected CPUs. @@ -835,15 +837,8 @@ static void init_amd(struct cpuinfo_x86 *c) cpu_detect_cache_sizes(c); - /* Multi core CPU? */ - if (c->extended_cpuid_level >= 0x80000008) { - amd_detect_cmp(c); - srat_detect_node(c); - } - -#ifdef CONFIG_X86_32 - detect_ht(c); -#endif + amd_detect_cmp(c); + srat_detect_node(c); init_amd_cacheinfo(c); diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 7416fc206b4a0e3f17be821e932d9fd840c03079..3e435f88621d2aa38708c1b2107b933aca62eaeb 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -22,14 +22,17 @@ #include #include #include +#include #include #include #include #include #include +#include static void __init spectre_v2_select_mitigation(void); static void __init ssb_select_mitigation(void); +static void __init l1tf_select_mitigation(void); /* * Our boot-time value of the SPEC_CTRL MSR. We read it once so that any @@ -55,6 +58,12 @@ void __init check_bugs(void) { identify_boot_cpu(); + /* + * identify_boot_cpu() initialized SMT support information, let the + * core code know. + */ + cpu_smt_check_topology_early(); + if (!IS_ENABLED(CONFIG_SMP)) { pr_info("CPU: "); print_cpu_info(&boot_cpu_data); @@ -81,6 +90,8 @@ void __init check_bugs(void) */ ssb_select_mitigation(); + l1tf_select_mitigation(); + #ifdef CONFIG_X86_32 /* * Check whether we are able to run this kernel safely on SMP. @@ -311,23 +322,6 @@ static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void) return cmd; } -/* Check for Skylake-like CPUs (for RSB handling) */ -static bool __init is_skylake_era(void) -{ - if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && - boot_cpu_data.x86 == 6) { - switch (boot_cpu_data.x86_model) { - case INTEL_FAM6_SKYLAKE_MOBILE: - case INTEL_FAM6_SKYLAKE_DESKTOP: - case INTEL_FAM6_SKYLAKE_X: - case INTEL_FAM6_KABYLAKE_MOBILE: - case INTEL_FAM6_KABYLAKE_DESKTOP: - return true; - } - } - return false; -} - static void __init spectre_v2_select_mitigation(void) { enum spectre_v2_mitigation_cmd cmd = spectre_v2_parse_cmdline(); @@ -388,22 +382,15 @@ static void __init spectre_v2_select_mitigation(void) pr_info("%s\n", spectre_v2_strings[mode]); /* - * If neither SMEP nor PTI are available, there is a risk of - * hitting userspace addresses in the RSB after a context switch - * from a shallow call stack to a deeper one. To prevent this fill - * the entire RSB, even when using IBRS. + * If spectre v2 protection has been enabled, unconditionally fill + * RSB during a context switch; this protects against two independent + * issues: * - * Skylake era CPUs have a separate issue with *underflow* of the - * RSB, when they will predict 'ret' targets from the generic BTB. - * The proper mitigation for this is IBRS. If IBRS is not supported - * or deactivated in favour of retpolines the RSB fill on context - * switch is required. + * - RSB underflow (and switch to BTB) on Skylake+ + * - SpectreRSB variant of spectre v2 on X86_BUG_SPECTRE_V2 CPUs */ - if ((!boot_cpu_has(X86_FEATURE_PTI) && - !boot_cpu_has(X86_FEATURE_SMEP)) || is_skylake_era()) { - setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW); - pr_info("Spectre v2 mitigation: Filling RSB on context switch\n"); - } + setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW); + pr_info("Spectre v2 / SpectreRSB mitigation: Filling RSB on context switch\n"); /* Initialize Indirect Branch Prediction Barrier if supported */ if (boot_cpu_has(X86_FEATURE_IBPB)) { @@ -654,8 +641,160 @@ void x86_spec_ctrl_setup_ap(void) x86_amd_ssb_disable(); } +#undef pr_fmt +#define pr_fmt(fmt) "L1TF: " fmt + +/* Default mitigation for L1TF-affected CPUs */ +enum l1tf_mitigations l1tf_mitigation __ro_after_init = L1TF_MITIGATION_FLUSH; +#if IS_ENABLED(CONFIG_KVM_INTEL) +EXPORT_SYMBOL_GPL(l1tf_mitigation); +#endif +enum vmx_l1d_flush_state l1tf_vmx_mitigation = VMENTER_L1D_FLUSH_AUTO; +EXPORT_SYMBOL_GPL(l1tf_vmx_mitigation); + +/* + * These CPUs all support 44bits physical address space internally in the + * cache but CPUID can report a smaller number of physical address bits. + * + * The L1TF mitigation uses the top most address bit for the inversion of + * non present PTEs. When the installed memory reaches into the top most + * address bit due to memory holes, which has been observed on machines + * which report 36bits physical address bits and have 32G RAM installed, + * then the mitigation range check in l1tf_select_mitigation() triggers. + * This is a false positive because the mitigation is still possible due to + * the fact that the cache uses 44bit internally. Use the cache bits + * instead of the reported physical bits and adjust them on the affected + * machines to 44bit if the reported bits are less than 44. + */ +static void override_cache_bits(struct cpuinfo_x86 *c) +{ + if (c->x86 != 6) + return; + + switch (c->x86_model) { + case INTEL_FAM6_NEHALEM: + case INTEL_FAM6_WESTMERE: + case INTEL_FAM6_SANDYBRIDGE: + case INTEL_FAM6_IVYBRIDGE: + case INTEL_FAM6_HASWELL_CORE: + case INTEL_FAM6_HASWELL_ULT: + case INTEL_FAM6_HASWELL_GT3E: + case INTEL_FAM6_BROADWELL_CORE: + case INTEL_FAM6_BROADWELL_GT3E: + case INTEL_FAM6_SKYLAKE_MOBILE: + case INTEL_FAM6_SKYLAKE_DESKTOP: + case INTEL_FAM6_KABYLAKE_MOBILE: + case INTEL_FAM6_KABYLAKE_DESKTOP: + if (c->x86_cache_bits < 44) + c->x86_cache_bits = 44; + break; + } +} + +static void __init l1tf_select_mitigation(void) +{ + u64 half_pa; + + if (!boot_cpu_has_bug(X86_BUG_L1TF)) + return; + + override_cache_bits(&boot_cpu_data); + + switch (l1tf_mitigation) { + case L1TF_MITIGATION_OFF: + case L1TF_MITIGATION_FLUSH_NOWARN: + case L1TF_MITIGATION_FLUSH: + break; + case L1TF_MITIGATION_FLUSH_NOSMT: + case L1TF_MITIGATION_FULL: + cpu_smt_disable(false); + break; + case L1TF_MITIGATION_FULL_FORCE: + cpu_smt_disable(true); + break; + } + +#if CONFIG_PGTABLE_LEVELS == 2 + pr_warn("Kernel not compiled for PAE. No mitigation for L1TF\n"); + return; +#endif + + half_pa = (u64)l1tf_pfn_limit() << PAGE_SHIFT; + if (e820__mapped_any(half_pa, ULLONG_MAX - half_pa, E820_TYPE_RAM)) { + pr_warn("System has more than MAX_PA/2 memory. L1TF mitigation not effective.\n"); + pr_info("You may make it effective by booting the kernel with mem=%llu parameter.\n", + half_pa); + pr_info("However, doing so will make a part of your RAM unusable.\n"); + pr_info("Reading https://www.kernel.org/doc/html/latest/admin-guide/l1tf.html might help you decide.\n"); + return; + } + + setup_force_cpu_cap(X86_FEATURE_L1TF_PTEINV); +} + +static int __init l1tf_cmdline(char *str) +{ + if (!boot_cpu_has_bug(X86_BUG_L1TF)) + return 0; + + if (!str) + return -EINVAL; + + if (!strcmp(str, "off")) + l1tf_mitigation = L1TF_MITIGATION_OFF; + else if (!strcmp(str, "flush,nowarn")) + l1tf_mitigation = L1TF_MITIGATION_FLUSH_NOWARN; + else if (!strcmp(str, "flush")) + l1tf_mitigation = L1TF_MITIGATION_FLUSH; + else if (!strcmp(str, "flush,nosmt")) + l1tf_mitigation = L1TF_MITIGATION_FLUSH_NOSMT; + else if (!strcmp(str, "full")) + l1tf_mitigation = L1TF_MITIGATION_FULL; + else if (!strcmp(str, "full,force")) + l1tf_mitigation = L1TF_MITIGATION_FULL_FORCE; + + return 0; +} +early_param("l1tf", l1tf_cmdline); + +#undef pr_fmt + #ifdef CONFIG_SYSFS +#define L1TF_DEFAULT_MSG "Mitigation: PTE Inversion" + +#if IS_ENABLED(CONFIG_KVM_INTEL) +static const char *l1tf_vmx_states[] = { + [VMENTER_L1D_FLUSH_AUTO] = "auto", + [VMENTER_L1D_FLUSH_NEVER] = "vulnerable", + [VMENTER_L1D_FLUSH_COND] = "conditional cache flushes", + [VMENTER_L1D_FLUSH_ALWAYS] = "cache flushes", + [VMENTER_L1D_FLUSH_EPT_DISABLED] = "EPT disabled", + [VMENTER_L1D_FLUSH_NOT_REQUIRED] = "flush not necessary" +}; + +static ssize_t l1tf_show_state(char *buf) +{ + if (l1tf_vmx_mitigation == VMENTER_L1D_FLUSH_AUTO) + return sprintf(buf, "%s\n", L1TF_DEFAULT_MSG); + + if (l1tf_vmx_mitigation == VMENTER_L1D_FLUSH_EPT_DISABLED || + (l1tf_vmx_mitigation == VMENTER_L1D_FLUSH_NEVER && + cpu_smt_control == CPU_SMT_ENABLED)) + return sprintf(buf, "%s; VMX: %s\n", L1TF_DEFAULT_MSG, + l1tf_vmx_states[l1tf_vmx_mitigation]); + + return sprintf(buf, "%s; VMX: %s, SMT %s\n", L1TF_DEFAULT_MSG, + l1tf_vmx_states[l1tf_vmx_mitigation], + cpu_smt_control == CPU_SMT_ENABLED ? "vulnerable" : "disabled"); +} +#else +static ssize_t l1tf_show_state(char *buf) +{ + return sprintf(buf, "%s\n", L1TF_DEFAULT_MSG); +} +#endif + static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr, char *buf, unsigned int bug) { @@ -681,6 +820,10 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr case X86_BUG_SPEC_STORE_BYPASS: return sprintf(buf, "%s\n", ssb_strings[ssb_mode]); + case X86_BUG_L1TF: + if (boot_cpu_has(X86_FEATURE_L1TF_PTEINV)) + return l1tf_show_state(buf); + break; default: break; } @@ -707,4 +850,9 @@ ssize_t cpu_show_spec_store_bypass(struct device *dev, struct device_attribute * { return cpu_show_common(dev, attr, buf, X86_BUG_SPEC_STORE_BYPASS); } + +ssize_t cpu_show_l1tf(struct device *dev, struct device_attribute *attr, char *buf) +{ + return cpu_show_common(dev, attr, buf, X86_BUG_L1TF); +} #endif diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 48e98964ecadb71754c32f300d2e99544e733400..7d2a7890a823eb7cabe8c274cb331dd348172058 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -66,6 +66,13 @@ cpumask_var_t cpu_callin_mask; /* representing cpus for which sibling maps can be computed */ cpumask_var_t cpu_sibling_setup_mask; +/* Number of siblings per CPU package */ +int smp_num_siblings = 1; +EXPORT_SYMBOL(smp_num_siblings); + +/* Last level cache ID of each logical CPU */ +DEFINE_PER_CPU_READ_MOSTLY(u16, cpu_llc_id) = BAD_APICID; + /* correctly size the local cpu masks */ void __init setup_cpu_local_masks(void) { @@ -614,33 +621,36 @@ static void cpu_detect_tlb(struct cpuinfo_x86 *c) tlb_lld_4m[ENTRIES], tlb_lld_1g[ENTRIES]); } -void detect_ht(struct cpuinfo_x86 *c) +int detect_ht_early(struct cpuinfo_x86 *c) { #ifdef CONFIG_SMP u32 eax, ebx, ecx, edx; - int index_msb, core_bits; - static bool printed; if (!cpu_has(c, X86_FEATURE_HT)) - return; + return -1; if (cpu_has(c, X86_FEATURE_CMP_LEGACY)) - goto out; + return -1; if (cpu_has(c, X86_FEATURE_XTOPOLOGY)) - return; + return -1; cpuid(1, &eax, &ebx, &ecx, &edx); smp_num_siblings = (ebx & 0xff0000) >> 16; - - if (smp_num_siblings == 1) { + if (smp_num_siblings == 1) pr_info_once("CPU0: Hyper-Threading is disabled\n"); - goto out; - } +#endif + return 0; +} - if (smp_num_siblings <= 1) - goto out; +void detect_ht(struct cpuinfo_x86 *c) +{ +#ifdef CONFIG_SMP + int index_msb, core_bits; + + if (detect_ht_early(c) < 0) + return; index_msb = get_count_order(smp_num_siblings); c->phys_proc_id = apic->phys_pkg_id(c->initial_apicid, index_msb); @@ -653,15 +663,6 @@ void detect_ht(struct cpuinfo_x86 *c) c->cpu_core_id = apic->phys_pkg_id(c->initial_apicid, index_msb) & ((1 << core_bits) - 1); - -out: - if (!printed && (c->x86_max_cores * smp_num_siblings) > 1) { - pr_info("CPU: Physical Processor ID: %d\n", - c->phys_proc_id); - pr_info("CPU: Processor Core ID: %d\n", - c->cpu_core_id); - printed = 1; - } #endif } @@ -889,6 +890,7 @@ static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c) } } #endif + c->x86_cache_bits = c->x86_phys_bits; } static const __initconst struct x86_cpu_id cpu_no_speculation[] = { @@ -933,6 +935,21 @@ static const __initconst struct x86_cpu_id cpu_no_spec_store_bypass[] = { {} }; +static const __initconst struct x86_cpu_id cpu_no_l1tf[] = { + /* in addition to cpu_no_speculation */ + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT1 }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT2 }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_AIRMONT }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_MERRIFIELD }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_MOOREFIELD }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_GOLDMONT }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_DENVERTON }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_GEMINI_LAKE }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_XEON_PHI_KNL }, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_XEON_PHI_KNM }, + {} +}; + static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c) { u64 ia32_cap = 0; @@ -958,6 +975,11 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c) return; setup_force_cpu_bug(X86_BUG_CPU_MELTDOWN); + + if (x86_match_cpu(cpu_no_l1tf)) + return; + + setup_force_cpu_bug(X86_BUG_L1TF); } /* diff --git a/arch/x86/kernel/cpu/cpu.h b/arch/x86/kernel/cpu/cpu.h index 37672d299e357430f2d16941905e352e9e89f648..cca588407dca80915a1eec1197a84e0d1f13e8f4 100644 --- a/arch/x86/kernel/cpu/cpu.h +++ b/arch/x86/kernel/cpu/cpu.h @@ -47,6 +47,8 @@ extern const struct cpu_dev *const __x86_cpu_dev_start[], extern void get_cpu_cap(struct cpuinfo_x86 *c); extern void cpu_detect_cache_sizes(struct cpuinfo_x86 *c); +extern int detect_extended_topology_early(struct cpuinfo_x86 *c); +extern int detect_ht_early(struct cpuinfo_x86 *c); unsigned int aperfmperf_get_khz(int cpu); diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 0b2330e191694c638b40cc2b5b7f797d31e18d6e..574dcdc092abdcfadfe834424c3e079144ecc51f 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -150,6 +150,9 @@ static bool bad_spectre_microcode(struct cpuinfo_x86 *c) if (cpu_has(c, X86_FEATURE_HYPERVISOR)) return false; + if (c->x86 != 6) + return false; + for (i = 0; i < ARRAY_SIZE(spectre_bad_microcodes); i++) { if (c->x86_model == spectre_bad_microcodes[i].model && c->x86_stepping == spectre_bad_microcodes[i].stepping) @@ -301,6 +304,13 @@ static void early_init_intel(struct cpuinfo_x86 *c) } check_mpx_erratum(c); + + /* + * Get the number of SMT siblings early from the extended topology + * leaf, if available. Otherwise try the legacy SMT detection. + */ + if (detect_extended_topology_early(c) < 0) + detect_ht_early(c); } #ifdef CONFIG_X86_32 diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c index 48179928ff38cf12476ce27cd096383aee1feb93..9d33dbf2489e2b6679131ecb3938aa4c382347f0 100644 --- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -504,6 +504,7 @@ static enum ucode_state apply_microcode_amd(int cpu) struct microcode_amd *mc_amd; struct ucode_cpu_info *uci; struct ucode_patch *p; + enum ucode_state ret; u32 rev, dummy; BUG_ON(raw_smp_processor_id() != cpu); @@ -521,9 +522,8 @@ static enum ucode_state apply_microcode_amd(int cpu) /* need to apply patch? */ if (rev >= mc_amd->hdr.patch_id) { - c->microcode = rev; - uci->cpu_sig.rev = rev; - return UCODE_OK; + ret = UCODE_OK; + goto out; } if (__apply_microcode_amd(mc_amd)) { @@ -531,13 +531,21 @@ static enum ucode_state apply_microcode_amd(int cpu) cpu, mc_amd->hdr.patch_id); return UCODE_ERROR; } - pr_info("CPU%d: new patch_level=0x%08x\n", cpu, - mc_amd->hdr.patch_id); - uci->cpu_sig.rev = mc_amd->hdr.patch_id; - c->microcode = mc_amd->hdr.patch_id; + rev = mc_amd->hdr.patch_id; + ret = UCODE_UPDATED; + + pr_info("CPU%d: new patch_level=0x%08x\n", cpu, rev); - return UCODE_UPDATED; +out: + uci->cpu_sig.rev = rev; + c->microcode = rev; + + /* Update boot_cpu_data's revision too, if we're on the BSP: */ + if (c->cpu_index == boot_cpu_data.cpu_index) + boot_cpu_data.microcode = rev; + + return ret; } static int install_equiv_cpu_table(const u8 *buf) diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index 4fc0e08a30b9981faf809132ef74a129bd1572a1..387a8f44fba1ecca7436e2cf2ae6b0cdbb43977f 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -509,12 +509,20 @@ static struct platform_device *microcode_pdev; static int check_online_cpus(void) { - if (num_online_cpus() == num_present_cpus()) - return 0; + unsigned int cpu; - pr_err("Not all CPUs online, aborting microcode update.\n"); + /* + * Make sure all CPUs are online. It's fine for SMT to be disabled if + * all the primary threads are still online. + */ + for_each_present_cpu(cpu) { + if (topology_is_primary_thread(cpu) && !cpu_online(cpu)) { + pr_err("Not all CPUs online, aborting microcode update.\n"); + return -EINVAL; + } + } - return -EINVAL; + return 0; } static atomic_t late_cpus_in; diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index 1c2cfa0644aa979c97cc01a42925a44c25f9f852..16936a24795c8457b789f7b428216cfc5bd1fb4e 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -190,8 +190,11 @@ static void save_microcode_patch(void *data, unsigned int size) p = memdup_patch(data, size); if (!p) pr_err("Error allocating buffer %p\n", data); - else + else { list_replace(&iter->plist, &p->plist); + kfree(iter->data); + kfree(iter); + } } } @@ -792,6 +795,7 @@ static enum ucode_state apply_microcode_intel(int cpu) struct ucode_cpu_info *uci = ucode_cpu_info + cpu; struct cpuinfo_x86 *c = &cpu_data(cpu); struct microcode_intel *mc; + enum ucode_state ret; static int prev_rev; u32 rev; @@ -814,9 +818,8 @@ static enum ucode_state apply_microcode_intel(int cpu) */ rev = intel_get_microcode_revision(); if (rev >= mc->hdr.rev) { - uci->cpu_sig.rev = rev; - c->microcode = rev; - return UCODE_OK; + ret = UCODE_OK; + goto out; } /* @@ -845,10 +848,17 @@ static enum ucode_state apply_microcode_intel(int cpu) prev_rev = rev; } + ret = UCODE_UPDATED; + +out: uci->cpu_sig.rev = rev; - c->microcode = rev; + c->microcode = rev; + + /* Update boot_cpu_data's revision too, if we're on the BSP: */ + if (c->cpu_index == boot_cpu_data.cpu_index) + boot_cpu_data.microcode = rev; - return UCODE_UPDATED; + return ret; } static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size, diff --git a/arch/x86/kernel/cpu/topology.c b/arch/x86/kernel/cpu/topology.c index b099024d339c386929dbda450a328bc2b3887377..19c6e800e8162ae90ec852b3437c9d5e7be5e8d4 100644 --- a/arch/x86/kernel/cpu/topology.c +++ b/arch/x86/kernel/cpu/topology.c @@ -27,16 +27,13 @@ * exists, use it for populating initial_apicid and cpu topology * detection. */ -void detect_extended_topology(struct cpuinfo_x86 *c) +int detect_extended_topology_early(struct cpuinfo_x86 *c) { #ifdef CONFIG_SMP - unsigned int eax, ebx, ecx, edx, sub_index; - unsigned int ht_mask_width, core_plus_mask_width; - unsigned int core_select_mask, core_level_siblings; - static bool printed; + unsigned int eax, ebx, ecx, edx; if (c->cpuid_level < 0xb) - return; + return -1; cpuid_count(0xb, SMT_LEVEL, &eax, &ebx, &ecx, &edx); @@ -44,7 +41,7 @@ void detect_extended_topology(struct cpuinfo_x86 *c) * check if the cpuid leaf 0xb is actually implemented. */ if (ebx == 0 || (LEAFB_SUBTYPE(ecx) != SMT_TYPE)) - return; + return -1; set_cpu_cap(c, X86_FEATURE_XTOPOLOGY); @@ -52,10 +49,30 @@ void detect_extended_topology(struct cpuinfo_x86 *c) * initial apic id, which also represents 32-bit extended x2apic id. */ c->initial_apicid = edx; + smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx); +#endif + return 0; +} + +/* + * Check for extended topology enumeration cpuid leaf 0xb and if it + * exists, use it for populating initial_apicid and cpu topology + * detection. + */ +void detect_extended_topology(struct cpuinfo_x86 *c) +{ +#ifdef CONFIG_SMP + unsigned int eax, ebx, ecx, edx, sub_index; + unsigned int ht_mask_width, core_plus_mask_width; + unsigned int core_select_mask, core_level_siblings; + + if (detect_extended_topology_early(c) < 0) + return; /* * Populate HT related information from sub-leaf level 0. */ + cpuid_count(0xb, SMT_LEVEL, &eax, &ebx, &ecx, &edx); core_level_siblings = smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx); core_plus_mask_width = ht_mask_width = BITS_SHIFT_NEXT_LEVEL(eax); @@ -86,15 +103,5 @@ void detect_extended_topology(struct cpuinfo_x86 *c) c->apicid = apic->phys_pkg_id(c->initial_apicid, 0); c->x86_max_cores = (core_level_siblings / smp_num_siblings); - - if (!printed) { - pr_info("CPU: Physical Processor ID: %d\n", - c->phys_proc_id); - if (c->x86_max_cores > 1) - pr_info("CPU: Processor Core ID: %d\n", - c->cpu_core_id); - printed = 1; - } - return; #endif } diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index a2d8a3908670993c898cd0d22cbdd6742e51b4da..224de37821e4ed74ae7d1a4a1f17f848b5584832 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -298,7 +299,10 @@ void oops_end(unsigned long flags, struct pt_regs *regs, int signr) * We're not going to return, but we might be on an IST stack or * have very little stack space left. Rewind the stack and kill * the task. + * Before we rewind the stack, we have to tell KASAN that we're going to + * reuse the task stack and that existing poisons are invalid. */ + kasan_unpoison_task_stack(current); rewind_stack_do_exit(signr); } NOKPROBE_SYMBOL(oops_end); diff --git a/arch/x86/kernel/eisa.c b/arch/x86/kernel/eisa.c index f260e452e4f8726237618efe4b9526938d31d81d..e8c8c5d78dbdd38b1089f5dc87cf3450644fe487 100644 --- a/arch/x86/kernel/eisa.c +++ b/arch/x86/kernel/eisa.c @@ -7,11 +7,17 @@ #include #include +#include + static __init int eisa_bus_probe(void) { - void __iomem *p = ioremap(0x0FFFD9, 4); + void __iomem *p; + + if (xen_pv_domain() && !xen_initial_domain()) + return 0; - if (readl(p) == 'E' + ('I'<<8) + ('S'<<16) + ('A'<<24)) + p = ioremap(0x0FFFD9, 4); + if (p && readl(p) == 'E' + ('I' << 8) + ('S' << 16) + ('A' << 24)) EISA_bus = 1; iounmap(p); return 0; diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index f92a6593de1ec651d244d43d16acbd8d49959e4b..2ea85b32421a02d5f3f8e6643757610576841e3c 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index 01ebcb6f263e39accb3f8e53ab7eb5372e0726f7..7acb87cb2da83309f86df91dcc239044037ee1e3 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -27,6 +27,7 @@ #include #include +#include #include #include diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c index 7ba5d819ebe3b351ff4124ded8c598adfcb1a5f1..45b5c6c4a55edac132a855e47502eacb62225045 100644 --- a/arch/x86/kernel/head64.c +++ b/arch/x86/kernel/head64.c @@ -31,6 +31,7 @@ #include #include #include +#include /* * Manage page tables very early on. @@ -93,7 +94,8 @@ unsigned long __head __startup_64(unsigned long physaddr, pud[511] += load_delta; pmd = fixup_pointer(level2_fixmap_pgt, physaddr); - pmd[506] += load_delta; + for (i = FIXMAP_PMD_TOP; i > FIXMAP_PMD_TOP - FIXMAP_PMD_NUM; i--) + pmd[i] += load_delta; /* * Set up the identity mapping for the switchover. These diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index 0f545b3cf926787bd986d763c843498540ef530d..8d59dfe629a96e8a53183cfb9cb4d867e039c520 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S @@ -24,6 +24,7 @@ #include "../entry/calling.h" #include #include +#include #ifdef CONFIG_PARAVIRT #include @@ -438,13 +439,20 @@ NEXT_PAGE(level2_kernel_pgt) KERNEL_IMAGE_SIZE/PMD_SIZE) NEXT_PAGE(level2_fixmap_pgt) - .fill 506,8,0 - .quad level1_fixmap_pgt - __START_KERNEL_map + _PAGE_TABLE_NOENC - /* 8MB reserved for vsyscalls + a 2MB hole = 4 + 1 entries */ - .fill 5,8,0 + .fill (512 - 4 - FIXMAP_PMD_NUM),8,0 + pgtno = 0 + .rept (FIXMAP_PMD_NUM) + .quad level1_fixmap_pgt + (pgtno << PAGE_SHIFT) - __START_KERNEL_map \ + + _PAGE_TABLE_NOENC; + pgtno = pgtno + 1 + .endr + /* 6 MB reserved space + a 2MB hole */ + .fill 4,8,0 NEXT_PAGE(level1_fixmap_pgt) + .rept (FIXMAP_PMD_NUM) .fill 512,8,0 + .endr #undef PMDS diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index 8ce4212e2b8d0f139e543e05e7e284ee25ee856d..afa1a204bc6d69029a2520725b174ba201dd7cd7 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/x86/kernel/i8259.c b/arch/x86/kernel/i8259.c index 8f5cb2c7060cfc29b46ec24669ec418dfdf0c0df..02abc134367ff0c0d93d2ac2758006a5f0925637 100644 --- a/arch/x86/kernel/i8259.c +++ b/arch/x86/kernel/i8259.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/x86/kernel/idt.c b/arch/x86/kernel/idt.c index 0c5256653d6c5256eef39c5dc6768d49e40889a0..38c3d5790970cfaa3bd0e52018dff7095acf270f 100644 --- a/arch/x86/kernel/idt.c +++ b/arch/x86/kernel/idt.c @@ -8,6 +8,7 @@ #include #include #include +#include struct idt_data { unsigned int vector; diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index aa9d51eea9d0e806e51122421e77d67dd31bb027..3c2326b598208ceb1254468e3dd9a01e23ec0e67 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c index c1bdbd3d3232cb83d07bfa4ce604ae0b620c796a..95600a99ae93652dbbd4143c9e538e808911bb24 100644 --- a/arch/x86/kernel/irq_32.c +++ b/arch/x86/kernel/irq_32.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include diff --git a/arch/x86/kernel/irq_64.c b/arch/x86/kernel/irq_64.c index d86e344f5b3debfed504b72a7c0f83f36fe16387..0469cd078db15c0c26700fc7a50f9c3f8144ff2a 100644 --- a/arch/x86/kernel/irq_64.c +++ b/arch/x86/kernel/irq_64.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include diff --git a/arch/x86/kernel/irqinit.c b/arch/x86/kernel/irqinit.c index 1e4094eba15e95e6f9b3c6f19de6d748bb894dd1..40f83d0d7b8a3e8da20a46a9f899c39b064d46c4 100644 --- a/arch/x86/kernel/irqinit.c +++ b/arch/x86/kernel/irqinit.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c index f24cd9f1799a062a8df2c3c25bb164ba28537f89..928b0c6083c9cc5953fd5f47867ff218efaea910 100644 --- a/arch/x86/kernel/kexec-bzimage64.c +++ b/arch/x86/kernel/kexec-bzimage64.c @@ -532,7 +532,7 @@ static int bzImage64_cleanup(void *loader_data) static int bzImage64_verify_sig(const char *kernel, unsigned long kernel_len) { return verify_pefile_signature(kernel, kernel_len, - NULL, + VERIFY_USE_SECONDARY_KEYRING, VERIFYING_KEXEC_PE_SIGNATURE); } #endif diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index f1030c522e06c868146f7e13f13a6b9c54cbaf67..65452d555f0514178528bfc13d96c7bbd8d19cab 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c @@ -63,6 +63,7 @@ #include #include #include +#include #include "common.h" @@ -394,8 +395,6 @@ int __copy_instruction(u8 *dest, u8 *src, struct insn *insn) - (u8 *) dest; if ((s64) (s32) newdisp != newdisp) { pr_err("Kprobes error: new displacement does not fit into s32 (%llx)\n", newdisp); - pr_err("\tSrc: %p, Dest: %p, old disp: %x\n", - src, dest, insn->displacement.value); return 0; } disp = (u8 *) dest + insn_offset_displacement(insn); @@ -621,8 +620,7 @@ static int reenter_kprobe(struct kprobe *p, struct pt_regs *regs, * Raise a BUG or we'll continue in an endless reentering loop * and eventually a stack overflow. */ - printk(KERN_WARNING "Unrecoverable kprobe detected at %p.\n", - p->addr); + pr_err("Unrecoverable kprobe detected.\n"); dump_kprobe(p); BUG(); default: diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c index 5b609e28ce3f40514be95ac47cddd5a0c4d77ab0..48703d430a2fb46470deef90963947c08e7ef945 100644 --- a/arch/x86/kernel/kvmclock.c +++ b/arch/x86/kernel/kvmclock.c @@ -143,6 +143,7 @@ static unsigned long kvm_get_tsc_khz(void) src = &hv_clock[cpu].pvti; tsc_khz = pvclock_tsc_khz(src); put_cpu(); + setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ); return tsc_khz; } diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c index e1df9ef5d78c95516f877bfdbeeceaf3ba09cde0..f3559b84cd7536f44f16d3b316e149e4a17f261f 100644 --- a/arch/x86/kernel/paravirt.c +++ b/arch/x86/kernel/paravirt.c @@ -88,10 +88,12 @@ unsigned paravirt_patch_call(void *insnbuf, struct branch *b = insnbuf; unsigned long delta = (unsigned long)target - (addr+5); - if (tgt_clobbers & ~site_clobbers) - return len; /* target would clobber too much for this site */ - if (len < 5) + if (len < 5) { +#ifdef CONFIG_RETPOLINE + WARN_ONCE("Failing to patch indirect CALL in %ps\n", (void *)addr); +#endif return len; /* call too long for patch site */ + } b->opcode = 0xe8; /* call */ b->delta = delta; @@ -106,8 +108,12 @@ unsigned paravirt_patch_jmp(void *insnbuf, const void *target, struct branch *b = insnbuf; unsigned long delta = (unsigned long)target - (addr+5); - if (len < 5) + if (len < 5) { +#ifdef CONFIG_RETPOLINE + WARN_ONCE("Failing to patch indirect JMP in %ps\n", (void *)addr); +#endif return len; /* call too long for patch site */ + } b->opcode = 0xe9; /* jmp */ b->delta = delta; diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index fa093b77689f82ee547481067ba85026ebdfd29c..cbeecfcc66d68b3ae44eaa075ba7be9e49f1063b 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -370,6 +370,7 @@ start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp) start_thread_common(regs, new_ip, new_sp, __USER_CS, __USER_DS, 0); } +EXPORT_SYMBOL_GPL(start_thread); #ifdef CONFIG_COMPAT void compat_start_thread(struct pt_regs *regs, u32 new_ip, u32 new_sp) diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index efbcf5283520ba28741388cb29b9e2cb5ede6376..dcb00acb6583c83432552f6032fb22f3d33fe980 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -852,6 +852,12 @@ void __init setup_arch(char **cmdline_p) memblock_reserve(__pa_symbol(_text), (unsigned long)__bss_stop - (unsigned long)_text); + /* + * Make sure page 0 is always reserved because on systems with + * L1TF its contents can be leaked to user processes. + */ + memblock_reserve(0, PAGE_SIZE); + early_reserve_initrd(); /* diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c index 5c574dff4c1a00990c6e6d8e5d993cc2777c6c6f..04adc8d60aed82178caf3a099d66b497a6c11bcf 100644 --- a/arch/x86/kernel/smp.c +++ b/arch/x86/kernel/smp.c @@ -261,6 +261,7 @@ __visible void __irq_entry smp_reschedule_interrupt(struct pt_regs *regs) { ack_APIC_irq(); inc_irq_stat(irq_resched_count); + kvm_set_cpu_l1tf_flush_l1d(); if (trace_resched_ipi_enabled()) { /* diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 344d3c160f8d779773a7c25ff4f971d5c2273622..30447d210f37e272a08d7af707544ed2622ebf49 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -78,13 +78,7 @@ #include #include #include - -/* Number of siblings per CPU package */ -int smp_num_siblings = 1; -EXPORT_SYMBOL(smp_num_siblings); - -/* Last level cache ID of each logical CPU */ -DEFINE_PER_CPU_READ_MOSTLY(u16, cpu_llc_id) = BAD_APICID; +#include /* representing HT siblings of each logical CPU */ DEFINE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_sibling_map); @@ -229,6 +223,11 @@ static void notrace start_secondary(void *unused) #ifdef CONFIG_X86_32 /* switch away from the initial page table */ load_cr3(swapper_pg_dir); + /* + * Initialize the CR4 shadow before doing anything that could + * try to read it. + */ + cr4_init_shadow(); __flush_tlb_all(); #endif load_current_idt(); @@ -311,6 +310,23 @@ int topology_update_package_map(unsigned int pkg, unsigned int cpu) return 0; } +/** + * topology_is_primary_thread - Check whether CPU is the primary SMT thread + * @cpu: CPU to check + */ +bool topology_is_primary_thread(unsigned int cpu) +{ + return apic_id_is_primary_thread(per_cpu(x86_cpu_to_apicid, cpu)); +} + +/** + * topology_smt_supported - Check whether SMT is supported by the CPUs + */ +bool topology_smt_supported(void) +{ + return smp_num_siblings > 1; +} + /** * topology_phys_to_logical_pkg - Map a physical package id to a logical * diff --git a/arch/x86/kernel/time.c b/arch/x86/kernel/time.c index 879af864d99afd6c8645f0d74fe71bf6a2bade07..49a5c394f3ed45af7afd9e1841b6833ec120ad90 100644 --- a/arch/x86/kernel/time.c +++ b/arch/x86/kernel/time.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include diff --git a/arch/x86/kernel/tsc_msr.c b/arch/x86/kernel/tsc_msr.c index 19afdbd7d0a77c8f5511cf2de616d24c5259dbae..5532d1be76879b452ca3c072de807eb4d9509b85 100644 --- a/arch/x86/kernel/tsc_msr.c +++ b/arch/x86/kernel/tsc_msr.c @@ -12,6 +12,7 @@ #include #include #include +#include #define MAX_NUM_FREQS 9 diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 2ef2f1fe875bf7aa908876014a134d6e91e13e9e..d755e0d44ac1cdddb13e8da33d611e2bd9cad6f6 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -220,6 +220,28 @@ static const u64 shadow_acc_track_saved_bits_mask = PT64_EPT_READABLE_MASK | PT64_EPT_EXECUTABLE_MASK; static const u64 shadow_acc_track_saved_bits_shift = PT64_SECOND_AVAIL_BITS_SHIFT; +/* + * This mask must be set on all non-zero Non-Present or Reserved SPTEs in order + * to guard against L1TF attacks. + */ +static u64 __read_mostly shadow_nonpresent_or_rsvd_mask; + +/* + * The number of high-order 1 bits to use in the mask above. + */ +static const u64 shadow_nonpresent_or_rsvd_mask_len = 5; + +/* + * In some cases, we need to preserve the GFN of a non-present or reserved + * SPTE when we usurp the upper five bits of the physical address space to + * defend against L1TF, e.g. for MMIO SPTEs. To preserve the GFN, we'll + * shift bits of the GFN that overlap with shadow_nonpresent_or_rsvd_mask + * left into the reserved bits, i.e. the GFN in the SPTE will be split into + * high and low parts. This mask covers the lower bits of the GFN. + */ +static u64 __read_mostly shadow_nonpresent_or_rsvd_lower_gfn_mask; + + static void mmu_spte_set(u64 *sptep, u64 spte); static void mmu_free_roots(struct kvm_vcpu *vcpu); @@ -308,9 +330,13 @@ static void mark_mmio_spte(struct kvm_vcpu *vcpu, u64 *sptep, u64 gfn, { unsigned int gen = kvm_current_mmio_generation(vcpu); u64 mask = generation_mmio_spte_mask(gen); + u64 gpa = gfn << PAGE_SHIFT; access &= ACC_WRITE_MASK | ACC_USER_MASK; - mask |= shadow_mmio_value | access | gfn << PAGE_SHIFT; + mask |= shadow_mmio_value | access; + mask |= gpa | shadow_nonpresent_or_rsvd_mask; + mask |= (gpa & shadow_nonpresent_or_rsvd_mask) + << shadow_nonpresent_or_rsvd_mask_len; trace_mark_mmio_spte(sptep, gfn, access, gen); mmu_spte_set(sptep, mask); @@ -323,8 +349,12 @@ static bool is_mmio_spte(u64 spte) static gfn_t get_mmio_spte_gfn(u64 spte) { - u64 mask = generation_mmio_spte_mask(MMIO_GEN_MASK) | shadow_mmio_mask; - return (spte & ~mask) >> PAGE_SHIFT; + u64 gpa = spte & shadow_nonpresent_or_rsvd_lower_gfn_mask; + + gpa |= (spte >> shadow_nonpresent_or_rsvd_mask_len) + & shadow_nonpresent_or_rsvd_mask; + + return gpa >> PAGE_SHIFT; } static unsigned get_mmio_spte_access(u64 spte) @@ -381,8 +411,10 @@ void kvm_mmu_set_mask_ptes(u64 user_mask, u64 accessed_mask, } EXPORT_SYMBOL_GPL(kvm_mmu_set_mask_ptes); -void kvm_mmu_clear_all_pte_masks(void) +static void kvm_mmu_reset_all_pte_masks(void) { + u8 low_phys_bits; + shadow_user_mask = 0; shadow_accessed_mask = 0; shadow_dirty_mask = 0; @@ -391,6 +423,23 @@ void kvm_mmu_clear_all_pte_masks(void) shadow_mmio_mask = 0; shadow_present_mask = 0; shadow_acc_track_mask = 0; + + /* + * If the CPU has 46 or less physical address bits, then set an + * appropriate mask to guard against L1TF attacks. Otherwise, it is + * assumed that the CPU is not vulnerable to L1TF. + */ + low_phys_bits = boot_cpu_data.x86_phys_bits; + if (boot_cpu_data.x86_phys_bits < + 52 - shadow_nonpresent_or_rsvd_mask_len) { + shadow_nonpresent_or_rsvd_mask = + rsvd_bits(boot_cpu_data.x86_phys_bits - + shadow_nonpresent_or_rsvd_mask_len, + boot_cpu_data.x86_phys_bits - 1); + low_phys_bits -= shadow_nonpresent_or_rsvd_mask_len; + } + shadow_nonpresent_or_rsvd_lower_gfn_mask = + GENMASK_ULL(low_phys_bits - 1, PAGE_SHIFT); } static int is_cpuid_PSE36(void) @@ -3825,6 +3874,7 @@ int kvm_handle_page_fault(struct kvm_vcpu *vcpu, u64 error_code, { int r = 1; + vcpu->arch.l1tf_flush_l1d = true; switch (vcpu->arch.apf.host_apf_reason) { default: trace_kvm_page_fault(fault_address, error_code); @@ -5472,7 +5522,7 @@ static void mmu_destroy_caches(void) int kvm_mmu_module_init(void) { - kvm_mmu_clear_all_pte_masks(); + kvm_mmu_reset_all_pte_masks(); pte_list_desc_cache = kmem_cache_create("pte_list_desc", sizeof(struct pte_list_desc), diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index cfa155078ebb70b006788c2692d8a3ee9f6e4422..f6bebcec60b4e507cb6a468ed2173c3d629d7b49 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -175,6 +175,8 @@ struct vcpu_svm { uint64_t sysenter_eip; uint64_t tsc_aux; + u64 msr_decfg; + u64 next_rip; u64 host_user_msrs[NR_HOST_SAVE_USER_MSRS]; @@ -1616,6 +1618,7 @@ static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) u32 dummy; u32 eax = 1; + vcpu->arch.microcode_version = 0x01000065; svm->spec_ctrl = 0; svm->virt_spec_ctrl = 0; @@ -3555,6 +3558,22 @@ static int cr8_write_interception(struct vcpu_svm *svm) return 0; } +static int svm_get_msr_feature(struct kvm_msr_entry *msr) +{ + msr->data = 0; + + switch (msr->index) { + case MSR_F10H_DECFG: + if (boot_cpu_has(X86_FEATURE_LFENCE_RDTSC)) + msr->data |= MSR_F10H_DECFG_LFENCE_SERIALIZE; + break; + default: + return 1; + } + + return 0; +} + static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) { struct vcpu_svm *svm = to_svm(vcpu); @@ -3637,9 +3656,6 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) msr_info->data = svm->virt_spec_ctrl; break; - case MSR_IA32_UCODE_REV: - msr_info->data = 0x01000065; - break; case MSR_F15H_IC_CFG: { int family, model; @@ -3657,6 +3673,9 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) msr_info->data = 0x1E; } break; + case MSR_F10H_DECFG: + msr_info->data = svm->msr_decfg; + break; default: return kvm_get_msr_common(vcpu, msr_info); } @@ -3845,6 +3864,24 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) case MSR_VM_IGNNE: vcpu_unimpl(vcpu, "unimplemented wrmsr: 0x%x data 0x%llx\n", ecx, data); break; + case MSR_F10H_DECFG: { + struct kvm_msr_entry msr_entry; + + msr_entry.index = msr->index; + if (svm_get_msr_feature(&msr_entry)) + return 1; + + /* Check the supported bits */ + if (data & ~msr_entry.data) + return 1; + + /* Don't allow the guest to change a bit, #GP */ + if (!msr->host_initiated && (data ^ msr_entry.data)) + return 1; + + svm->msr_decfg = data; + break; + } case MSR_IA32_APICBASE: if (kvm_vcpu_apicv_active(vcpu)) avic_update_vapic_bar(to_svm(vcpu), data); @@ -5030,8 +5067,6 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) clgi(); - local_irq_enable(); - /* * If this vCPU has touched SPEC_CTRL, restore the guest's value if * it's non-zero. Since vmentry is serialising on affected CPUs, there @@ -5040,6 +5075,8 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) */ x86_spec_ctrl_set_guest(svm->spec_ctrl, svm->virt_spec_ctrl); + local_irq_enable(); + asm volatile ( "push %%" _ASM_BP "; \n\t" "mov %c[rbx](%[svm]), %%" _ASM_BX " \n\t" @@ -5162,12 +5199,12 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) if (unlikely(!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL))) svm->spec_ctrl = native_read_msr(MSR_IA32_SPEC_CTRL); - x86_spec_ctrl_restore_host(svm->spec_ctrl, svm->virt_spec_ctrl); - reload_tss(vcpu); local_irq_disable(); + x86_spec_ctrl_restore_host(svm->spec_ctrl, svm->virt_spec_ctrl); + vcpu->arch.cr2 = svm->vmcb->save.cr2; vcpu->arch.regs[VCPU_REGS_RAX] = svm->vmcb->save.rax; vcpu->arch.regs[VCPU_REGS_RSP] = svm->vmcb->save.rsp; @@ -5588,6 +5625,7 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = { .vcpu_unblocking = svm_vcpu_unblocking, .update_bp_intercept = update_bp_intercept, + .get_msr_feature = svm_get_msr_feature, .get_msr = svm_get_msr, .set_msr = svm_set_msr, .get_segment_base = svm_get_segment_base, diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 8d000fde14140e43f7b535a19c2346033bdbb203..fd46d890296c9e98b472e79d55bbef8ca8c7b0f4 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -191,6 +191,156 @@ module_param(ple_window_max, int, S_IRUGO); extern const ulong vmx_return; +static DEFINE_STATIC_KEY_FALSE(vmx_l1d_should_flush); +static DEFINE_STATIC_KEY_FALSE(vmx_l1d_flush_cond); +static DEFINE_MUTEX(vmx_l1d_flush_mutex); + +/* Storage for pre module init parameter parsing */ +static enum vmx_l1d_flush_state __read_mostly vmentry_l1d_flush_param = VMENTER_L1D_FLUSH_AUTO; + +static const struct { + const char *option; + bool for_parse; +} vmentry_l1d_param[] = { + [VMENTER_L1D_FLUSH_AUTO] = {"auto", true}, + [VMENTER_L1D_FLUSH_NEVER] = {"never", true}, + [VMENTER_L1D_FLUSH_COND] = {"cond", true}, + [VMENTER_L1D_FLUSH_ALWAYS] = {"always", true}, + [VMENTER_L1D_FLUSH_EPT_DISABLED] = {"EPT disabled", false}, + [VMENTER_L1D_FLUSH_NOT_REQUIRED] = {"not required", false}, +}; + +#define L1D_CACHE_ORDER 4 +static void *vmx_l1d_flush_pages; + +static int vmx_setup_l1d_flush(enum vmx_l1d_flush_state l1tf) +{ + struct page *page; + unsigned int i; + + if (!enable_ept) { + l1tf_vmx_mitigation = VMENTER_L1D_FLUSH_EPT_DISABLED; + return 0; + } + + if (boot_cpu_has(X86_FEATURE_ARCH_CAPABILITIES)) { + u64 msr; + + rdmsrl(MSR_IA32_ARCH_CAPABILITIES, msr); + if (msr & ARCH_CAP_SKIP_VMENTRY_L1DFLUSH) { + l1tf_vmx_mitigation = VMENTER_L1D_FLUSH_NOT_REQUIRED; + return 0; + } + } + + /* If set to auto use the default l1tf mitigation method */ + if (l1tf == VMENTER_L1D_FLUSH_AUTO) { + switch (l1tf_mitigation) { + case L1TF_MITIGATION_OFF: + l1tf = VMENTER_L1D_FLUSH_NEVER; + break; + case L1TF_MITIGATION_FLUSH_NOWARN: + case L1TF_MITIGATION_FLUSH: + case L1TF_MITIGATION_FLUSH_NOSMT: + l1tf = VMENTER_L1D_FLUSH_COND; + break; + case L1TF_MITIGATION_FULL: + case L1TF_MITIGATION_FULL_FORCE: + l1tf = VMENTER_L1D_FLUSH_ALWAYS; + break; + } + } else if (l1tf_mitigation == L1TF_MITIGATION_FULL_FORCE) { + l1tf = VMENTER_L1D_FLUSH_ALWAYS; + } + + if (l1tf != VMENTER_L1D_FLUSH_NEVER && !vmx_l1d_flush_pages && + !boot_cpu_has(X86_FEATURE_FLUSH_L1D)) { + page = alloc_pages(GFP_KERNEL, L1D_CACHE_ORDER); + if (!page) + return -ENOMEM; + vmx_l1d_flush_pages = page_address(page); + + /* + * Initialize each page with a different pattern in + * order to protect against KSM in the nested + * virtualization case. + */ + for (i = 0; i < 1u << L1D_CACHE_ORDER; ++i) { + memset(vmx_l1d_flush_pages + i * PAGE_SIZE, i + 1, + PAGE_SIZE); + } + } + + l1tf_vmx_mitigation = l1tf; + + if (l1tf != VMENTER_L1D_FLUSH_NEVER) + static_branch_enable(&vmx_l1d_should_flush); + else + static_branch_disable(&vmx_l1d_should_flush); + + if (l1tf == VMENTER_L1D_FLUSH_COND) + static_branch_enable(&vmx_l1d_flush_cond); + else + static_branch_disable(&vmx_l1d_flush_cond); + return 0; +} + +static int vmentry_l1d_flush_parse(const char *s) +{ + unsigned int i; + + if (s) { + for (i = 0; i < ARRAY_SIZE(vmentry_l1d_param); i++) { + if (vmentry_l1d_param[i].for_parse && + sysfs_streq(s, vmentry_l1d_param[i].option)) + return i; + } + } + return -EINVAL; +} + +static int vmentry_l1d_flush_set(const char *s, const struct kernel_param *kp) +{ + int l1tf, ret; + + l1tf = vmentry_l1d_flush_parse(s); + if (l1tf < 0) + return l1tf; + + if (!boot_cpu_has(X86_BUG_L1TF)) + return 0; + + /* + * Has vmx_init() run already? If not then this is the pre init + * parameter parsing. In that case just store the value and let + * vmx_init() do the proper setup after enable_ept has been + * established. + */ + if (l1tf_vmx_mitigation == VMENTER_L1D_FLUSH_AUTO) { + vmentry_l1d_flush_param = l1tf; + return 0; + } + + mutex_lock(&vmx_l1d_flush_mutex); + ret = vmx_setup_l1d_flush(l1tf); + mutex_unlock(&vmx_l1d_flush_mutex); + return ret; +} + +static int vmentry_l1d_flush_get(char *s, const struct kernel_param *kp) +{ + if (WARN_ON_ONCE(l1tf_vmx_mitigation >= ARRAY_SIZE(vmentry_l1d_param))) + return sprintf(s, "???\n"); + + return sprintf(s, "%s\n", vmentry_l1d_param[l1tf_vmx_mitigation].option); +} + +static const struct kernel_param_ops vmentry_l1d_flush_ops = { + .set = vmentry_l1d_flush_set, + .get = vmentry_l1d_flush_get, +}; +module_param_cb(vmentry_l1d_flush, &vmentry_l1d_flush_ops, NULL, 0644); + #define NR_AUTOLOAD_MSRS 8 struct vmcs { @@ -567,6 +717,11 @@ static inline int pi_test_sn(struct pi_desc *pi_desc) (unsigned long *)&pi_desc->control); } +struct vmx_msrs { + unsigned int nr; + struct vmx_msr_entry val[NR_AUTOLOAD_MSRS]; +}; + struct vcpu_vmx { struct kvm_vcpu vcpu; unsigned long host_rsp; @@ -594,18 +749,21 @@ struct vcpu_vmx { /* * loaded_vmcs points to the VMCS currently used in this vcpu. For a * non-nested (L1) guest, it always points to vmcs01. For a nested - * guest (L2), it points to a different VMCS. + * guest (L2), it points to a different VMCS. loaded_cpu_state points + * to the VMCS whose state is loaded into the CPU registers that only + * need to be switched when transitioning to/from the kernel; a NULL + * value indicates that host state is loaded. */ struct loaded_vmcs vmcs01; struct loaded_vmcs *loaded_vmcs; + struct loaded_vmcs *loaded_cpu_state; bool __launched; /* temporary, used in vmx_vcpu_run */ struct msr_autoload { - unsigned nr; - struct vmx_msr_entry guest[NR_AUTOLOAD_MSRS]; - struct vmx_msr_entry host[NR_AUTOLOAD_MSRS]; + struct vmx_msrs guest; + struct vmx_msrs host; } msr_autoload; + struct { - int loaded; u16 fs_sel, gs_sel, ldt_sel; #ifdef CONFIG_X86_64 u16 ds_sel, es_sel; @@ -1967,9 +2125,20 @@ static void clear_atomic_switch_msr_special(struct vcpu_vmx *vmx, vm_exit_controls_clearbit(vmx, exit); } +static int find_msr(struct vmx_msrs *m, unsigned int msr) +{ + unsigned int i; + + for (i = 0; i < m->nr; ++i) { + if (m->val[i].index == msr) + return i; + } + return -ENOENT; +} + static void clear_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr) { - unsigned i; + int i; struct msr_autoload *m = &vmx->msr_autoload; switch (msr) { @@ -1990,18 +2159,21 @@ static void clear_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr) } break; } + i = find_msr(&m->guest, msr); + if (i < 0) + goto skip_guest; + --m->guest.nr; + m->guest.val[i] = m->guest.val[m->guest.nr]; + vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->guest.nr); - for (i = 0; i < m->nr; ++i) - if (m->guest[i].index == msr) - break; - - if (i == m->nr) +skip_guest: + i = find_msr(&m->host, msr); + if (i < 0) return; - --m->nr; - m->guest[i] = m->guest[m->nr]; - m->host[i] = m->host[m->nr]; - vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->nr); - vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->nr); + + --m->host.nr; + m->host.val[i] = m->host.val[m->host.nr]; + vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->host.nr); } static void add_atomic_switch_msr_special(struct vcpu_vmx *vmx, @@ -2016,9 +2188,9 @@ static void add_atomic_switch_msr_special(struct vcpu_vmx *vmx, } static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr, - u64 guest_val, u64 host_val) + u64 guest_val, u64 host_val, bool entry_only) { - unsigned i; + int i, j = 0; struct msr_autoload *m = &vmx->msr_autoload; switch (msr) { @@ -2053,24 +2225,31 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr, wrmsrl(MSR_IA32_PEBS_ENABLE, 0); } - for (i = 0; i < m->nr; ++i) - if (m->guest[i].index == msr) - break; + i = find_msr(&m->guest, msr); + if (!entry_only) + j = find_msr(&m->host, msr); - if (i == NR_AUTOLOAD_MSRS) { + if (i == NR_AUTOLOAD_MSRS || j == NR_AUTOLOAD_MSRS) { printk_once(KERN_WARNING "Not enough msr switch entries. " "Can't add msr %x\n", msr); return; - } else if (i == m->nr) { - ++m->nr; - vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->nr); - vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->nr); } + if (i < 0) { + i = m->guest.nr++; + vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->guest.nr); + } + m->guest.val[i].index = msr; + m->guest.val[i].value = guest_val; - m->guest[i].index = msr; - m->guest[i].value = guest_val; - m->host[i].index = msr; - m->host[i].value = host_val; + if (entry_only) + return; + + if (j < 0) { + j = m->host.nr++; + vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->host.nr); + } + m->host.val[j].index = msr; + m->host.val[j].value = host_val; } static bool update_transition_efer(struct vcpu_vmx *vmx, int efer_offset) @@ -2114,7 +2293,7 @@ static bool update_transition_efer(struct vcpu_vmx *vmx, int efer_offset) guest_efer &= ~EFER_LME; if (guest_efer != host_efer) add_atomic_switch_msr(vmx, MSR_EFER, - guest_efer, host_efer); + guest_efer, host_efer, false); return false; } else { guest_efer &= ~ignore_bits; @@ -2161,10 +2340,11 @@ static void vmx_save_host_state(struct kvm_vcpu *vcpu) struct vcpu_vmx *vmx = to_vmx(vcpu); int i; - if (vmx->host_state.loaded) + if (vmx->loaded_cpu_state) return; - vmx->host_state.loaded = 1; + vmx->loaded_cpu_state = vmx->loaded_vmcs; + /* * Set host fs and gs selectors. Unfortunately, 22.2.3 does not * allow segment selectors with cpl > 0 or ti == 1. @@ -2215,11 +2395,14 @@ static void vmx_save_host_state(struct kvm_vcpu *vcpu) static void __vmx_load_host_state(struct vcpu_vmx *vmx) { - if (!vmx->host_state.loaded) + if (!vmx->loaded_cpu_state) return; + WARN_ON_ONCE(vmx->loaded_cpu_state != vmx->loaded_vmcs); + ++vmx->vcpu.stat.host_state_reload; - vmx->host_state.loaded = 0; + vmx->loaded_cpu_state = NULL; + #ifdef CONFIG_X86_64 if (is_long_mode(&vmx->vcpu)) rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base); @@ -3266,6 +3449,11 @@ static inline bool vmx_feature_control_msr_valid(struct kvm_vcpu *vcpu, return !(val & ~valid_bits); } +static int vmx_get_msr_feature(struct kvm_msr_entry *msr) +{ + return 1; +} + /* * Reads an msr value (of 'msr_index') into 'pdata'. * Returns 0 on success, non-0 otherwise. @@ -3523,7 +3711,7 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) vcpu->arch.ia32_xss = data; if (vcpu->arch.ia32_xss != host_xss) add_atomic_switch_msr(vmx, MSR_IA32_XSS, - vcpu->arch.ia32_xss, host_xss); + vcpu->arch.ia32_xss, host_xss, false); else clear_atomic_switch_msr(vmx, MSR_IA32_XSS); break; @@ -5714,9 +5902,9 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx) vmcs_write32(VM_EXIT_MSR_STORE_COUNT, 0); vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, 0); - vmcs_write64(VM_EXIT_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.host)); + vmcs_write64(VM_EXIT_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.host.val)); vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, 0); - vmcs_write64(VM_ENTRY_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.guest)); + vmcs_write64(VM_ENTRY_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.guest.val)); if (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_PAT) vmcs_write64(GUEST_IA32_PAT, vmx->vcpu.arch.pat); @@ -5736,8 +5924,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx) ++vmx->nmsrs; } - if (boot_cpu_has(X86_FEATURE_ARCH_CAPABILITIES)) - rdmsrl(MSR_IA32_ARCH_CAPABILITIES, vmx->arch_capabilities); + vmx->arch_capabilities = kvm_get_arch_capabilities(); vm_exit_controls_init(vmx, vmcs_config.vmexit_ctrl); @@ -5770,6 +5957,7 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) vmx->rmode.vm86_active = 0; vmx->spec_ctrl = 0; + vcpu->arch.microcode_version = 0x100000000ULL; vmx->vcpu.arch.regs[VCPU_REGS_RDX] = get_rdx_init_val(); kvm_set_cr8(vcpu, 0); @@ -6777,8 +6965,8 @@ static int handle_ept_misconfig(struct kvm_vcpu *vcpu) if (!static_cpu_has(X86_FEATURE_HYPERVISOR)) return kvm_skip_emulated_instruction(vcpu); else - return x86_emulate_instruction(vcpu, gpa, EMULTYPE_SKIP, - NULL, 0) == EMULATE_DONE; + return emulate_instruction(vcpu, EMULTYPE_SKIP) == + EMULATE_DONE; } ret = kvm_mmu_page_fault(vcpu, gpa, PFERR_RSVD_MASK, NULL, 0); @@ -7402,7 +7590,7 @@ static int handle_vmon(struct kvm_vcpu *vcpu) /* CPL=0 must be checked manually. */ if (vmx_get_cpl(vcpu)) { - kvm_queue_exception(vcpu, UD_VECTOR); + kvm_inject_gp(vcpu, 0); return 1; } @@ -7466,7 +7654,7 @@ static int handle_vmon(struct kvm_vcpu *vcpu) static int nested_vmx_check_permission(struct kvm_vcpu *vcpu) { if (vmx_get_cpl(vcpu)) { - kvm_queue_exception(vcpu, UD_VECTOR); + kvm_inject_gp(vcpu, 0); return 0; } @@ -7934,21 +8122,20 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu) /* Emulate the VMPTRST instruction */ static int handle_vmptrst(struct kvm_vcpu *vcpu) { - unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION); - u32 vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO); - gva_t vmcs_gva; + unsigned long exit_qual = vmcs_readl(EXIT_QUALIFICATION); + u32 instr_info = vmcs_read32(VMX_INSTRUCTION_INFO); + gpa_t current_vmptr = to_vmx(vcpu)->nested.current_vmptr; struct x86_exception e; + gva_t gva; if (!nested_vmx_check_permission(vcpu)) return 1; - if (get_vmx_mem_address(vcpu, exit_qualification, - vmx_instruction_info, true, &vmcs_gva)) + if (get_vmx_mem_address(vcpu, exit_qual, instr_info, true, &gva)) return 1; /* *_system ok, nested_vmx_check_permission has verified cpl=0 */ - if (kvm_write_guest_virt_system(vcpu, vmcs_gva, - (void *)&to_vmx(vcpu)->nested.current_vmptr, - sizeof(u64), &e)) { + if (kvm_write_guest_virt_system(vcpu, gva, (void *)¤t_vmptr, + sizeof(gpa_t), &e)) { kvm_inject_page_fault(vcpu, &e); return 1; } @@ -8987,6 +9174,76 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu) } } +/* + * Software based L1D cache flush which is used when microcode providing + * the cache control MSR is not loaded. + * + * The L1D cache is 32 KiB on Nehalem and later microarchitectures, but to + * flush it is required to read in 64 KiB because the replacement algorithm + * is not exactly LRU. This could be sized at runtime via topology + * information but as all relevant affected CPUs have 32KiB L1D cache size + * there is no point in doing so. + */ +static void vmx_l1d_flush(struct kvm_vcpu *vcpu) +{ + int size = PAGE_SIZE << L1D_CACHE_ORDER; + + /* + * This code is only executed when the the flush mode is 'cond' or + * 'always' + */ + if (static_branch_likely(&vmx_l1d_flush_cond)) { + bool flush_l1d; + + /* + * Clear the per-vcpu flush bit, it gets set again + * either from vcpu_run() or from one of the unsafe + * VMEXIT handlers. + */ + flush_l1d = vcpu->arch.l1tf_flush_l1d; + vcpu->arch.l1tf_flush_l1d = false; + + /* + * Clear the per-cpu flush bit, it gets set again from + * the interrupt handlers. + */ + flush_l1d |= kvm_get_cpu_l1tf_flush_l1d(); + kvm_clear_cpu_l1tf_flush_l1d(); + + if (!flush_l1d) + return; + } + + vcpu->stat.l1d_flush++; + + if (static_cpu_has(X86_FEATURE_FLUSH_L1D)) { + wrmsrl(MSR_IA32_FLUSH_CMD, L1D_FLUSH); + return; + } + + asm volatile( + /* First ensure the pages are in the TLB */ + "xorl %%eax, %%eax\n" + ".Lpopulate_tlb:\n\t" + "movzbl (%[flush_pages], %%" _ASM_AX "), %%ecx\n\t" + "addl $4096, %%eax\n\t" + "cmpl %%eax, %[size]\n\t" + "jne .Lpopulate_tlb\n\t" + "xorl %%eax, %%eax\n\t" + "cpuid\n\t" + /* Now fill the cache */ + "xorl %%eax, %%eax\n" + ".Lfill_cache:\n" + "movzbl (%[flush_pages], %%" _ASM_AX "), %%ecx\n\t" + "addl $64, %%eax\n\t" + "cmpl %%eax, %[size]\n\t" + "jne .Lfill_cache\n\t" + "lfence\n" + :: [flush_pages] "r" (vmx_l1d_flush_pages), + [size] "r" (size) + : "eax", "ebx", "ecx", "edx"); +} + static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr) { struct vmcs12 *vmcs12 = get_vmcs12(vcpu); @@ -9390,7 +9647,7 @@ static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx) clear_atomic_switch_msr(vmx, msrs[i].msr); else add_atomic_switch_msr(vmx, msrs[i].msr, msrs[i].guest, - msrs[i].host); + msrs[i].host, false); } static void vmx_arm_hv_timer(struct kvm_vcpu *vcpu) @@ -9483,6 +9740,9 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) vmx->__launched = vmx->loaded_vmcs->launched; + if (static_branch_unlikely(&vmx_l1d_should_flush)) + vmx_l1d_flush(vcpu); + asm( /* Store host registers */ "push %%" _ASM_DX "; push %%" _ASM_BP ";" @@ -9692,8 +9952,8 @@ static void vmx_switch_vmcs(struct kvm_vcpu *vcpu, struct loaded_vmcs *vmcs) return; cpu = get_cpu(); - vmx->loaded_vmcs = vmcs; vmx_vcpu_put(vcpu); + vmx->loaded_vmcs = vmcs; vmx_vcpu_load(vcpu, cpu); vcpu->cpu = cpu; put_cpu(); @@ -9835,6 +10095,37 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id) return ERR_PTR(err); } +#define L1TF_MSG_SMT "L1TF CPU bug present and SMT on, data leak possible. See CVE-2018-3646 and https://www.kernel.org/doc/html/latest/admin-guide/l1tf.html for details.\n" +#define L1TF_MSG_L1D "L1TF CPU bug present and virtualization mitigation disabled, data leak possible. See CVE-2018-3646 and https://www.kernel.org/doc/html/latest/admin-guide/l1tf.html for details.\n" + +static int vmx_vm_init(struct kvm *kvm) +{ + if (boot_cpu_has(X86_BUG_L1TF) && enable_ept) { + switch (l1tf_mitigation) { + case L1TF_MITIGATION_OFF: + case L1TF_MITIGATION_FLUSH_NOWARN: + /* 'I explicitly don't care' is set */ + break; + case L1TF_MITIGATION_FLUSH: + case L1TF_MITIGATION_FLUSH_NOSMT: + case L1TF_MITIGATION_FULL: + /* + * Warn upon starting the first VM in a potentially + * insecure environment. + */ + if (cpu_smt_control == CPU_SMT_ENABLED) + pr_warn_once(L1TF_MSG_SMT); + if (l1tf_vmx_mitigation == VMENTER_L1D_FLUSH_NEVER) + pr_warn_once(L1TF_MSG_L1D); + break; + case L1TF_MITIGATION_FULL_FORCE: + /* Flush is enforced */ + break; + } + } + return 0; +} + static void __init vmx_check_processor_compat(void *rtn) { struct vmcs_config vmcs_conf; @@ -10774,10 +11065,10 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, * Set the MSR load/store lists to match L0's settings. */ vmcs_write32(VM_EXIT_MSR_STORE_COUNT, 0); - vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.nr); - vmcs_write64(VM_EXIT_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.host)); - vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, vmx->msr_autoload.nr); - vmcs_write64(VM_ENTRY_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.guest)); + vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.host.nr); + vmcs_write64(VM_EXIT_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.host.val)); + vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, vmx->msr_autoload.guest.nr); + vmcs_write64(VM_ENTRY_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.guest.val)); /* * HOST_RSP is normally set correctly in vmx_vcpu_run() just before @@ -11202,6 +11493,9 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) if (ret) return ret; + /* Hide L1D cache contents from the nested guest. */ + vmx->vcpu.arch.l1tf_flush_l1d = true; + /* * If we're entering a halted L2 vcpu and the L2 vcpu won't be woken * by event injection, halt vcpu. @@ -11712,8 +12006,8 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason, vmx_segment_cache_clear(vmx); /* Update any VMCS fields that might have changed while L2 ran */ - vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.nr); - vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, vmx->msr_autoload.nr); + vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.host.nr); + vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, vmx->msr_autoload.guest.nr); vmcs_write64(TSC_OFFSET, vcpu->arch.tsc_offset); if (vmx->hv_deadline_tsc == -1) vmcs_clear_bits(PIN_BASED_VM_EXEC_CONTROL, @@ -12225,6 +12519,8 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = { .cpu_has_accelerated_tpr = report_flexpriority, .has_emulated_msr = vmx_has_emulated_msr, + .vm_init = vmx_vm_init, + .vcpu_create = vmx_create_vcpu, .vcpu_free = vmx_free_vcpu, .vcpu_reset = vmx_vcpu_reset, @@ -12234,6 +12530,7 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = { .vcpu_put = vmx_vcpu_put, .update_bp_intercept = update_exception_bitmap, + .get_msr_feature = vmx_get_msr_feature, .get_msr = vmx_get_msr, .set_msr = vmx_set_msr, .get_segment_base = vmx_get_segment_base, @@ -12341,22 +12638,18 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = { .setup_mce = vmx_setup_mce, }; -static int __init vmx_init(void) +static void vmx_cleanup_l1d_flush(void) { - int r = kvm_init(&vmx_x86_ops, sizeof(struct vcpu_vmx), - __alignof__(struct vcpu_vmx), THIS_MODULE); - if (r) - return r; - -#ifdef CONFIG_KEXEC_CORE - rcu_assign_pointer(crash_vmclear_loaded_vmcss, - crash_vmclear_local_loaded_vmcss); -#endif - - return 0; + if (vmx_l1d_flush_pages) { + free_pages((unsigned long)vmx_l1d_flush_pages, L1D_CACHE_ORDER); + vmx_l1d_flush_pages = NULL; + } + /* Restore state so sysfs ignores VMX */ + l1tf_vmx_mitigation = VMENTER_L1D_FLUSH_AUTO; } -static void __exit vmx_exit(void) + +static void vmx_exit(void) { #ifdef CONFIG_KEXEC_CORE RCU_INIT_POINTER(crash_vmclear_loaded_vmcss, NULL); @@ -12364,7 +12657,40 @@ static void __exit vmx_exit(void) #endif kvm_exit(); + + vmx_cleanup_l1d_flush(); } +module_exit(vmx_exit) +static int __init vmx_init(void) +{ + int r; + + r = kvm_init(&vmx_x86_ops, sizeof(struct vcpu_vmx), + __alignof__(struct vcpu_vmx), THIS_MODULE); + if (r) + return r; + + /* + * Must be called after kvm_init() so enable_ept is properly set + * up. Hand the parameter mitigation value in which was stored in + * the pre module init parser. If no parameter was given, it will + * contain 'auto' which will be turned into the default 'cond' + * mitigation mode. + */ + if (boot_cpu_has(X86_BUG_L1TF)) { + r = vmx_setup_l1d_flush(vmentry_l1d_flush_param); + if (r) { + vmx_exit(); + return r; + } + } + +#ifdef CONFIG_KEXEC_CORE + rcu_assign_pointer(crash_vmclear_loaded_vmcss, + crash_vmclear_local_loaded_vmcss); +#endif + + return 0; +} module_init(vmx_init) -module_exit(vmx_exit) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 2f3fe25639b345fe6de659369702b8aa9aa9b135..3856828ee1dc9c2fb2f670b2f4391ca3446947ae 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -181,6 +181,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { { "irq_injections", VCPU_STAT(irq_injections) }, { "nmi_injections", VCPU_STAT(nmi_injections) }, { "req_event", VCPU_STAT(req_event) }, + { "l1d_flush", VCPU_STAT(l1d_flush) }, { "mmu_shadow_zapped", VM_STAT(mmu_shadow_zapped) }, { "mmu_pte_write", VM_STAT(mmu_pte_write) }, { "mmu_pte_updated", VM_STAT(mmu_pte_updated) }, @@ -1041,6 +1042,71 @@ static u32 emulated_msrs[] = { static unsigned num_emulated_msrs; +/* + * List of msr numbers which are used to expose MSR-based features that + * can be used by a hypervisor to validate requested CPU features. + */ +static u32 msr_based_features[] = { + MSR_F10H_DECFG, + MSR_IA32_UCODE_REV, + MSR_IA32_ARCH_CAPABILITIES, +}; + +static unsigned int num_msr_based_features; + +u64 kvm_get_arch_capabilities(void) +{ + u64 data; + + rdmsrl_safe(MSR_IA32_ARCH_CAPABILITIES, &data); + + /* + * If we're doing cache flushes (either "always" or "cond") + * we will do one whenever the guest does a vmlaunch/vmresume. + * If an outer hypervisor is doing the cache flush for us + * (VMENTER_L1D_FLUSH_NESTED_VM), we can safely pass that + * capability to the guest too, and if EPT is disabled we're not + * vulnerable. Overall, only VMENTER_L1D_FLUSH_NEVER will + * require a nested hypervisor to do a flush of its own. + */ + if (l1tf_vmx_mitigation != VMENTER_L1D_FLUSH_NEVER) + data |= ARCH_CAP_SKIP_VMENTRY_L1DFLUSH; + + return data; +} +EXPORT_SYMBOL_GPL(kvm_get_arch_capabilities); + +static int kvm_get_msr_feature(struct kvm_msr_entry *msr) +{ + switch (msr->index) { + case MSR_IA32_ARCH_CAPABILITIES: + msr->data = kvm_get_arch_capabilities(); + break; + case MSR_IA32_UCODE_REV: + rdmsrl_safe(msr->index, &msr->data); + break; + default: + if (kvm_x86_ops->get_msr_feature(msr)) + return 1; + } + return 0; +} + +static int do_get_msr_feature(struct kvm_vcpu *vcpu, unsigned index, u64 *data) +{ + struct kvm_msr_entry msr; + int r; + + msr.index = index; + r = kvm_get_msr_feature(&msr); + if (r) + return r; + + *data = msr.data; + + return 0; +} + bool kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer) { if (efer & efer_reserved_bits) @@ -2156,7 +2222,6 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) switch (msr) { case MSR_AMD64_NB_CFG: - case MSR_IA32_UCODE_REV: case MSR_IA32_UCODE_WRITE: case MSR_VM_HSAVE_PA: case MSR_AMD64_PATCH_LOADER: @@ -2164,6 +2229,10 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) case MSR_AMD64_DC_CFG: break; + case MSR_IA32_UCODE_REV: + if (msr_info->host_initiated) + vcpu->arch.microcode_version = data; + break; case MSR_EFER: return set_efer(vcpu, data); case MSR_K7_HWCR: @@ -2450,7 +2519,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) msr_info->data = 0; break; case MSR_IA32_UCODE_REV: - msr_info->data = 0x100000000ULL; + msr_info->data = vcpu->arch.microcode_version; break; case MSR_MTRRcap: case 0x200 ... 0x2ff: @@ -2600,13 +2669,11 @@ static int __msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs *msrs, int (*do_msr)(struct kvm_vcpu *vcpu, unsigned index, u64 *data)) { - int i, idx; + int i; - idx = srcu_read_lock(&vcpu->kvm->srcu); for (i = 0; i < msrs->nmsrs; ++i) if (do_msr(vcpu, entries[i].index, &entries[i].data)) break; - srcu_read_unlock(&vcpu->kvm->srcu, idx); return i; } @@ -2705,6 +2772,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_SET_BOOT_CPU_ID: case KVM_CAP_SPLIT_IRQCHIP: case KVM_CAP_IMMEDIATE_EXIT: + case KVM_CAP_GET_MSR_FEATURES: r = 1; break; case KVM_CAP_ADJUST_CLOCK: @@ -2819,6 +2887,31 @@ long kvm_arch_dev_ioctl(struct file *filp, goto out; r = 0; break; + case KVM_GET_MSR_FEATURE_INDEX_LIST: { + struct kvm_msr_list __user *user_msr_list = argp; + struct kvm_msr_list msr_list; + unsigned int n; + + r = -EFAULT; + if (copy_from_user(&msr_list, user_msr_list, sizeof(msr_list))) + goto out; + n = msr_list.nmsrs; + msr_list.nmsrs = num_msr_based_features; + if (copy_to_user(user_msr_list, &msr_list, sizeof(msr_list))) + goto out; + r = -E2BIG; + if (n < msr_list.nmsrs) + goto out; + r = -EFAULT; + if (copy_to_user(user_msr_list->indices, &msr_based_features, + num_msr_based_features * sizeof(u32))) + goto out; + r = 0; + break; + } + case KVM_GET_MSRS: + r = msr_io(NULL, argp, do_get_msr_feature, 1); + break; } default: r = -EINVAL; @@ -3553,12 +3646,18 @@ long kvm_arch_vcpu_ioctl(struct file *filp, r = 0; break; } - case KVM_GET_MSRS: + case KVM_GET_MSRS: { + int idx = srcu_read_lock(&vcpu->kvm->srcu); r = msr_io(vcpu, argp, do_get_msr, 1); + srcu_read_unlock(&vcpu->kvm->srcu, idx); break; - case KVM_SET_MSRS: + } + case KVM_SET_MSRS: { + int idx = srcu_read_lock(&vcpu->kvm->srcu); r = msr_io(vcpu, argp, do_set_msr, 0); + srcu_read_unlock(&vcpu->kvm->srcu, idx); break; + } case KVM_TPR_ACCESS_REPORTING: { struct kvm_tpr_access_ctl tac; @@ -4333,6 +4432,19 @@ static void kvm_init_msr_list(void) j++; } num_emulated_msrs = j; + + for (i = j = 0; i < ARRAY_SIZE(msr_based_features); i++) { + struct kvm_msr_entry msr; + + msr.index = msr_based_features[i]; + if (kvm_get_msr_feature(&msr)) + continue; + + if (j < i) + msr_based_features[j] = msr_based_features[i]; + j++; + } + num_msr_based_features = j; } static int vcpu_mmio_write(struct kvm_vcpu *vcpu, gpa_t addr, int len, @@ -4573,6 +4685,9 @@ static int emulator_write_std(struct x86_emulate_ctxt *ctxt, gva_t addr, void *v int kvm_write_guest_virt_system(struct kvm_vcpu *vcpu, gva_t addr, void *val, unsigned int bytes, struct x86_exception *exception) { + /* kvm_write_guest_virt_system can pull in tons of pages. */ + vcpu->arch.l1tf_flush_l1d = true; + return kvm_write_guest_virt_helper(addr, val, bytes, vcpu, PFERR_WRITE_MASK, exception); } @@ -5701,6 +5816,8 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, bool writeback = true; bool write_fault_to_spt = vcpu->arch.write_fault_to_shadow_pgtable; + vcpu->arch.l1tf_flush_l1d = true; + /* * Clear write_fault_to_shadow_pgtable here to ensure it is * never reused. @@ -6077,20 +6194,22 @@ static void kvm_set_mmio_spte_mask(void) * Set the reserved bits and the present bit of an paging-structure * entry to generate page fault with PFER.RSV = 1. */ - /* Mask the reserved physical address bits. */ - mask = rsvd_bits(maxphyaddr, 51); + + /* + * Mask the uppermost physical address bit, which would be reserved as + * long as the supported physical address width is less than 52. + */ + mask = 1ull << 51; /* Set the present bit. */ mask |= 1ull; -#ifdef CONFIG_X86_64 /* * If reserved bit is not supported, clear the present bit to disable * mmio page fault. */ - if (maxphyaddr == 52) + if (IS_ENABLED(CONFIG_X86_64) && maxphyaddr == 52) mask &= ~1ull; -#endif kvm_mmu_set_mmio_spte_mask(mask, mask); } @@ -7146,6 +7265,7 @@ static int vcpu_run(struct kvm_vcpu *vcpu) struct kvm *kvm = vcpu->kvm; vcpu->srcu_idx = srcu_read_lock(&kvm->srcu); + vcpu->arch.l1tf_flush_l1d = true; for (;;) { if (kvm_vcpu_running(vcpu)) { @@ -8153,6 +8273,7 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) { + vcpu->arch.l1tf_flush_l1d = true; kvm_x86_ops->sched_in(vcpu, cpu); } diff --git a/arch/x86/lib/usercopy.c b/arch/x86/lib/usercopy.c index c8c6ad0d58b89c3621d0fcf11f45e00442ebf2a2..3f435d7fca5e62bc999e48c6a4f3e1c0fc86def9 100644 --- a/arch/x86/lib/usercopy.c +++ b/arch/x86/lib/usercopy.c @@ -7,6 +7,8 @@ #include #include +#include + /* * We rely on the nested NMI work to allow atomic faults from the NMI path; the * nested NMI paths are careful to preserve CR2. @@ -19,6 +21,9 @@ copy_from_user_nmi(void *to, const void __user *from, unsigned long n) if (__range_not_ok(from, n, TASK_SIZE)) return n; + if (!nmi_uaccess_okay()) + return n; + /* * Even though this function is typically called from NMI/IRQ context * disable pagefaults so that its behaviour is consistent even when diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 0133d26f16bea276206888ce4418634d27e38bad..794c35c4ca7360021a50c2a04d185eedbc577d52 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -24,6 +24,7 @@ #include /* emulate_vsyscall */ #include /* struct vm86 */ #include /* vma_pkey() */ +#include #define CREATE_TRACE_POINTS #include @@ -316,8 +317,6 @@ static noinline int vmalloc_fault(unsigned long address) if (!(address >= VMALLOC_START && address < VMALLOC_END)) return -1; - WARN_ON_ONCE(in_nmi()); - /* * Synchronize this task's top level page-table * with the 'reference' page table. diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index 071cbbbb60d96974a9f790fd6b69e3ff9ffe1162..94b8d90830d10c65ab16c1993cfb4d6f054fb628 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c @@ -4,6 +4,8 @@ #include #include #include /* for max_low_pfn */ +#include +#include #include #include @@ -880,3 +882,26 @@ void update_cache_mode_entry(unsigned entry, enum page_cache_mode cache) __cachemode2pte_tbl[cache] = __cm_idx2pte(entry); __pte2cachemode_tbl[entry] = cache; } + +#ifdef CONFIG_SWAP +unsigned long max_swapfile_size(void) +{ + unsigned long pages; + + pages = generic_max_swapfile_size(); + + if (boot_cpu_has_bug(X86_BUG_L1TF)) { + /* Limit the swap file size to MAX_PA/2 for L1TF workaround */ + unsigned long long l1tf_limit = l1tf_pfn_limit(); + /* + * We encode swap offsets also with 3 bits below those for pfn + * which makes the usable limit higher. + */ +#if CONFIG_PGTABLE_LEVELS > 2 + l1tf_limit <<= PAGE_SHIFT - SWP_OFFSET_FIRST_BIT; +#endif + pages = min_t(unsigned long long, l1tf_limit, pages); + } + return pages; +} +#endif diff --git a/arch/x86/mm/kmmio.c b/arch/x86/mm/kmmio.c index 7c868670963617865d2e9fb494a08b04a82b49cb..79eb55ce69a91f716c15524d56816604bcdcc100 100644 --- a/arch/x86/mm/kmmio.c +++ b/arch/x86/mm/kmmio.c @@ -126,24 +126,29 @@ static struct kmmio_fault_page *get_kmmio_fault_page(unsigned long addr) static void clear_pmd_presence(pmd_t *pmd, bool clear, pmdval_t *old) { + pmd_t new_pmd; pmdval_t v = pmd_val(*pmd); if (clear) { - *old = v & _PAGE_PRESENT; - v &= ~_PAGE_PRESENT; - } else /* presume this has been called with clear==true previously */ - v |= *old; - set_pmd(pmd, __pmd(v)); + *old = v; + new_pmd = pmd_mknotpresent(*pmd); + } else { + /* Presume this has been called with clear==true previously */ + new_pmd = __pmd(*old); + } + set_pmd(pmd, new_pmd); } static void clear_pte_presence(pte_t *pte, bool clear, pteval_t *old) { pteval_t v = pte_val(*pte); if (clear) { - *old = v & _PAGE_PRESENT; - v &= ~_PAGE_PRESENT; - } else /* presume this has been called with clear==true previously */ - v |= *old; - set_pte_atomic(pte, __pte(v)); + *old = v; + /* Nothing should care about address */ + pte_clear(&init_mm, 0, pte); + } else { + /* Presume this has been called with clear==true previously */ + set_pte_atomic(pte, __pte(*old)); + } } static int clear_page_presence(struct kmmio_fault_page *f, bool clear) diff --git a/arch/x86/mm/mmap.c b/arch/x86/mm/mmap.c index a9967982684649155cfcdc921d5247c8fbfe70d6..53f1c18b15bd361fa19fb75341a9e338b5301a3f 100644 --- a/arch/x86/mm/mmap.c +++ b/arch/x86/mm/mmap.c @@ -174,3 +174,24 @@ const char *arch_vma_name(struct vm_area_struct *vma) return "[mpx]"; return NULL; } + +/* + * Only allow root to set high MMIO mappings to PROT_NONE. + * This prevents an unpriv. user to set them to PROT_NONE and invert + * them, then pointing to valid memory for L1TF speculation. + * + * Note: for locked down kernels may want to disable the root override. + */ +bool pfn_modify_allowed(unsigned long pfn, pgprot_t prot) +{ + if (!boot_cpu_has_bug(X86_BUG_L1TF)) + return true; + if (!__pte_needs_invert(pgprot_val(prot))) + return true; + /* If it's real memory always allow */ + if (pfn_valid(pfn)) + return true; + if (pfn >= l1tf_pfn_limit() && !capable(CAP_SYS_ADMIN)) + return false; + return true; +} diff --git a/arch/x86/mm/numa_emulation.c b/arch/x86/mm/numa_emulation.c index 34a2a3bfde9c144623f4bfafbeb32404e4e3a21d..22cbad56acab8a698a0b0523745ea0be020cd0fc 100644 --- a/arch/x86/mm/numa_emulation.c +++ b/arch/x86/mm/numa_emulation.c @@ -61,7 +61,7 @@ static int __init emu_setup_memblk(struct numa_meminfo *ei, eb->nid = nid; if (emu_nid_to_phys[nid] == NUMA_NO_NODE) - emu_nid_to_phys[nid] = nid; + emu_nid_to_phys[nid] = pb->nid; pb->start += size; if (pb->start >= pb->end) { diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 4085897fef648700f669fea03907828296076fb8..464f53da3a6f53f198d860b0bef0ce9c41db362f 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c @@ -1006,8 +1006,8 @@ static long populate_pmd(struct cpa_data *cpa, pmd = pmd_offset(pud, start); - set_pmd(pmd, __pmd(cpa->pfn << PAGE_SHIFT | _PAGE_PSE | - massage_pgprot(pmd_pgprot))); + set_pmd(pmd, pmd_mkhuge(pfn_pmd(cpa->pfn, + canon_pgprot(pmd_pgprot)))); start += PMD_SIZE; cpa->pfn += PMD_SIZE >> PAGE_SHIFT; @@ -1079,8 +1079,8 @@ static int populate_pud(struct cpa_data *cpa, unsigned long start, p4d_t *p4d, * Map everything starting from the Gb boundary, possibly with 1G pages */ while (boot_cpu_has(X86_FEATURE_GBPAGES) && end - start >= PUD_SIZE) { - set_pud(pud, __pud(cpa->pfn << PAGE_SHIFT | _PAGE_PSE | - massage_pgprot(pud_pgprot))); + set_pud(pud, pud_mkhuge(pfn_pud(cpa->pfn, + canon_pgprot(pud_pgprot)))); start += PUD_SIZE; cpa->pfn += PUD_SIZE >> PAGE_SHIFT; diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c index c03c85e4fb6a6cb5fe35479a9e1cb63d65b7984c..aafd4edfa2ac6416b4332fa171658dcf4428d85b 100644 --- a/arch/x86/mm/pgtable.c +++ b/arch/x86/mm/pgtable.c @@ -573,6 +573,15 @@ void __native_set_fixmap(enum fixed_addresses idx, pte_t pte) { unsigned long address = __fix_to_virt(idx); +#ifdef CONFIG_X86_64 + /* + * Ensure that the static initial page tables are covering the + * fixmap completely. + */ + BUILD_BUG_ON(__end_of_permanent_fixed_addresses > + (FIXMAP_PMD_NUM * PTRS_PER_PTE)); +#endif + if (idx >= __end_of_fixed_addresses) { BUG(); return; @@ -712,28 +721,50 @@ int pmd_clear_huge(pmd_t *pmd) return 0; } +#ifdef CONFIG_X86_64 /** * pud_free_pmd_page - Clear pud entry and free pmd page. * @pud: Pointer to a PUD. + * @addr: Virtual address associated with pud. * - * Context: The pud range has been unmaped and TLB purged. + * Context: The pud range has been unmapped and TLB purged. * Return: 1 if clearing the entry succeeded. 0 otherwise. + * + * NOTE: Callers must allow a single page allocation. */ -int pud_free_pmd_page(pud_t *pud) +int pud_free_pmd_page(pud_t *pud, unsigned long addr) { - pmd_t *pmd; + pmd_t *pmd, *pmd_sv; + pte_t *pte; int i; if (pud_none(*pud)) return 1; pmd = (pmd_t *)pud_page_vaddr(*pud); + pmd_sv = (pmd_t *)__get_free_page(GFP_KERNEL); + if (!pmd_sv) + return 0; - for (i = 0; i < PTRS_PER_PMD; i++) - if (!pmd_free_pte_page(&pmd[i])) - return 0; + for (i = 0; i < PTRS_PER_PMD; i++) { + pmd_sv[i] = pmd[i]; + if (!pmd_none(pmd[i])) + pmd_clear(&pmd[i]); + } pud_clear(pud); + + /* INVLPG to clear all paging-structure caches */ + flush_tlb_kernel_range(addr, addr + PAGE_SIZE-1); + + for (i = 0; i < PTRS_PER_PMD; i++) { + if (!pmd_none(pmd_sv[i])) { + pte = (pte_t *)pmd_page_vaddr(pmd_sv[i]); + free_page((unsigned long)pte); + } + } + + free_page((unsigned long)pmd_sv); free_page((unsigned long)pmd); return 1; @@ -742,11 +773,12 @@ int pud_free_pmd_page(pud_t *pud) /** * pmd_free_pte_page - Clear pmd entry and free pte page. * @pmd: Pointer to a PMD. + * @addr: Virtual address associated with pmd. * - * Context: The pmd range has been unmaped and TLB purged. + * Context: The pmd range has been unmapped and TLB purged. * Return: 1 if clearing the entry succeeded. 0 otherwise. */ -int pmd_free_pte_page(pmd_t *pmd) +int pmd_free_pte_page(pmd_t *pmd, unsigned long addr) { pte_t *pte; @@ -755,8 +787,30 @@ int pmd_free_pte_page(pmd_t *pmd) pte = (pte_t *)pmd_page_vaddr(*pmd); pmd_clear(pmd); + + /* INVLPG to clear all paging-structure caches */ + flush_tlb_kernel_range(addr, addr + PAGE_SIZE-1); + free_page((unsigned long)pte); return 1; } + +#else /* !CONFIG_X86_64 */ + +int pud_free_pmd_page(pud_t *pud, unsigned long addr) +{ + return pud_none(*pud); +} + +/* + * Disable free page handling on x86-PAE. This assures that ioremap() + * does not update sync'd pmd entries. See vmalloc_sync_one(). + */ +int pmd_free_pte_page(pmd_t *pmd, unsigned long addr) +{ + return pmd_none(*pmd); +} + +#endif /* CONFIG_X86_64 */ #endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */ diff --git a/arch/x86/mm/pti.c b/arch/x86/mm/pti.c index ce38f165489b5a13d92091c8671879f30ce44e20..60c48f5d6b0eede5ed2456a8196fc7d9e8187afe 100644 --- a/arch/x86/mm/pti.c +++ b/arch/x86/mm/pti.c @@ -45,6 +45,7 @@ #include #include #include +#include #undef pr_fmt #define pr_fmt(fmt) "Kernel/User page tables isolation: " fmt @@ -161,7 +162,7 @@ static __init p4d_t *pti_user_pagetable_walk_p4d(unsigned long address) if (pgd_none(*pgd)) { unsigned long new_p4d_page = __get_free_page(gfp); - if (!new_p4d_page) + if (WARN_ON_ONCE(!new_p4d_page)) return NULL; set_pgd(pgd, __pgd(_KERNPG_TABLE | __pa(new_p4d_page))); @@ -180,13 +181,17 @@ static __init p4d_t *pti_user_pagetable_walk_p4d(unsigned long address) static __init pmd_t *pti_user_pagetable_walk_pmd(unsigned long address) { gfp_t gfp = (GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO); - p4d_t *p4d = pti_user_pagetable_walk_p4d(address); + p4d_t *p4d; pud_t *pud; + p4d = pti_user_pagetable_walk_p4d(address); + if (!p4d) + return NULL; + BUILD_BUG_ON(p4d_large(*p4d) != 0); if (p4d_none(*p4d)) { unsigned long new_pud_page = __get_free_page(gfp); - if (!new_pud_page) + if (WARN_ON_ONCE(!new_pud_page)) return NULL; set_p4d(p4d, __p4d(_KERNPG_TABLE | __pa(new_pud_page))); @@ -200,7 +205,7 @@ static __init pmd_t *pti_user_pagetable_walk_pmd(unsigned long address) } if (pud_none(*pud)) { unsigned long new_pmd_page = __get_free_page(gfp); - if (!new_pmd_page) + if (WARN_ON_ONCE(!new_pmd_page)) return NULL; set_pud(pud, __pud(_KERNPG_TABLE | __pa(new_pmd_page))); @@ -219,12 +224,16 @@ static __init pmd_t *pti_user_pagetable_walk_pmd(unsigned long address) * * Returns a pointer to a PTE on success, or NULL on failure. */ -static __init pte_t *pti_user_pagetable_walk_pte(unsigned long address) +static pte_t *pti_user_pagetable_walk_pte(unsigned long address) { gfp_t gfp = (GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO); - pmd_t *pmd = pti_user_pagetable_walk_pmd(address); + pmd_t *pmd; pte_t *pte; + pmd = pti_user_pagetable_walk_pmd(address); + if (!pmd) + return NULL; + /* We can't do anything sensible if we hit a large mapping. */ if (pmd_large(*pmd)) { WARN_ON(1); @@ -282,6 +291,10 @@ pti_clone_pmds(unsigned long start, unsigned long end, pmdval_t clear) p4d_t *p4d; pud_t *pud; + /* Overflow check */ + if (addr < start) + break; + pgd = pgd_offset_k(addr); if (WARN_ON(pgd_none(*pgd))) return; @@ -318,6 +331,9 @@ static void __init pti_clone_p4d(unsigned long addr) pgd_t *kernel_pgd; user_p4d = pti_user_pagetable_walk_p4d(addr); + if (!user_p4d) + return; + kernel_pgd = pgd_offset_k(addr); kernel_p4d = p4d_offset(kernel_pgd, addr); *user_p4d = *kernel_p4d; diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index 0c936435ea9398727da162fd76c5ee4dc4a91892..83a3f4c935fc5ff00d6d408d8e709b92a86722fb 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c @@ -292,6 +292,10 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, choose_new_asid(next, next_tlb_gen, &new_asid, &need_flush); + /* Let nmi_uaccess_okay() know that we're changing CR3. */ + this_cpu_write(cpu_tlbstate.loaded_mm, LOADED_MM_SWITCHING); + barrier(); + if (need_flush) { this_cpu_write(cpu_tlbstate.ctxs[new_asid].ctx_id, next->context.ctx_id); this_cpu_write(cpu_tlbstate.ctxs[new_asid].tlb_gen, next_tlb_gen); @@ -322,6 +326,9 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, if (next != &init_mm) this_cpu_write(cpu_tlbstate.last_ctx_id, next->context.ctx_id); + /* Make sure we write CR3 before loaded_mm. */ + barrier(); + this_cpu_write(cpu_tlbstate.loaded_mm, next); this_cpu_write(cpu_tlbstate.loaded_mm_asid, new_asid); } diff --git a/arch/x86/platform/intel-mid/device_libs/platform_mrfld_wdt.c b/arch/x86/platform/intel-mid/device_libs/platform_mrfld_wdt.c index 4f5fa65a10110344aa3d763fdf5b73a5d6652c0b..2acd6be133755872bad09e920fc0db1cb4911d2d 100644 --- a/arch/x86/platform/intel-mid/device_libs/platform_mrfld_wdt.c +++ b/arch/x86/platform/intel-mid/device_libs/platform_mrfld_wdt.c @@ -18,6 +18,7 @@ #include #include #include +#include #define TANGIER_EXT_TIMER0_MSI 12 diff --git a/arch/x86/platform/uv/tlb_uv.c b/arch/x86/platform/uv/tlb_uv.c index 0b530c53de1f8bc4edf2d4deac6b60620de4c491..34f9a9ce62360cb20d4f1354410a2df8c9a988a6 100644 --- a/arch/x86/platform/uv/tlb_uv.c +++ b/arch/x86/platform/uv/tlb_uv.c @@ -1285,6 +1285,7 @@ void uv_bau_message_interrupt(struct pt_regs *regs) struct msg_desc msgdesc; ack_APIC_irq(); + kvm_set_cpu_l1tf_flush_l1d(); time_start = get_cycles(); bcp = &per_cpu(bau_control, smp_processor_id()); diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index c9081c6671f0b7a05ecfaaf206e7e1ed2b1f456a..df208af3cd749415c67aa270adb5f225a3d42b37 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -3,6 +3,7 @@ #endif #include #include +#include #include #include diff --git a/arch/x86/xen/mmu_pv.c b/arch/x86/xen/mmu_pv.c index b3526a98a5a51151f95d26932fe612a79373af7c..8ed11a5b1a9d8b2618ec43daeb264e1245205dce 100644 --- a/arch/x86/xen/mmu_pv.c +++ b/arch/x86/xen/mmu_pv.c @@ -425,14 +425,13 @@ static void xen_set_pud(pud_t *ptr, pud_t val) static void xen_set_pte_atomic(pte_t *ptep, pte_t pte) { trace_xen_mmu_set_pte_atomic(ptep, pte); - set_64bit((u64 *)ptep, native_pte_val(pte)); + __xen_set_pte(ptep, pte); } static void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { trace_xen_mmu_pte_clear(mm, addr, ptep); - if (!xen_batched_set_pte(ptep, native_make_pte(0))) - native_pte_clear(mm, addr, ptep); + __xen_set_pte(ptep, native_make_pte(0)); } static void xen_pmd_clear(pmd_t *pmdp) @@ -1543,7 +1542,7 @@ static void __init xen_set_pte_init(pte_t *ptep, pte_t pte) pte = __pte_ma(((pte_val_ma(*ptep) & _PAGE_RW) | ~_PAGE_RW) & pte_val_ma(pte)); #endif - native_set_pte(ptep, pte); + __xen_set_pte(ptep, pte); } /* Early in boot, while setting up the initial pagetable, assume @@ -1880,7 +1879,7 @@ void __init xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn) /* L3_k[511] -> level2_fixmap_pgt */ convert_pfn_mfn(level3_kernel_pgt); - /* L3_k[511][506] -> level1_fixmap_pgt */ + /* L3_k[511][508-FIXMAP_PMD_NUM ... 507] -> level1_fixmap_pgt */ convert_pfn_mfn(level2_fixmap_pgt); /* We get [511][511] and have Xen's version of level2_kernel_pgt */ @@ -1925,7 +1924,11 @@ void __init xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn) set_page_prot(level2_ident_pgt, PAGE_KERNEL_RO); set_page_prot(level2_kernel_pgt, PAGE_KERNEL_RO); set_page_prot(level2_fixmap_pgt, PAGE_KERNEL_RO); - set_page_prot(level1_fixmap_pgt, PAGE_KERNEL_RO); + + for (i = 0; i < FIXMAP_PMD_NUM; i++) { + set_page_prot(level1_fixmap_pgt + i * PTRS_PER_PTE, + PAGE_KERNEL_RO); + } /* Pin down new L4 */ pin_pagetable_pfn(MMUEXT_PIN_L4_TABLE, diff --git a/arch/x86/xen/pmu.c b/arch/x86/xen/pmu.c index 7d00d4ad44d44d62f9a6a089a2c8d4a649e6aa08..95997e6c06960073c75b713cb2be76ec74c0886c 100644 --- a/arch/x86/xen/pmu.c +++ b/arch/x86/xen/pmu.c @@ -478,7 +478,7 @@ static void xen_convert_regs(const struct xen_pmu_regs *xen_regs, irqreturn_t xen_pmu_irq_handler(int irq, void *dev_id) { int err, ret = IRQ_NONE; - struct pt_regs regs; + struct pt_regs regs = {0}; const struct xen_pmu_data *xenpmu_data = get_xenpmu_data(); uint8_t xenpmu_flags = get_xenpmu_flags(); diff --git a/arch/xtensa/include/asm/cacheasm.h b/arch/xtensa/include/asm/cacheasm.h index 2041abb10a2352a4b1f4323f3e1f0d9bdfff36ec..34545ecfdd6b7332df7fb486930f1f35c5532640 100644 --- a/arch/xtensa/include/asm/cacheasm.h +++ b/arch/xtensa/include/asm/cacheasm.h @@ -31,16 +31,32 @@ * */ - .macro __loop_cache_all ar at insn size line_width - movi \ar, 0 + .macro __loop_cache_unroll ar at insn size line_width max_immed + + .if (1 << (\line_width)) > (\max_immed) + .set _reps, 1 + .elseif (2 << (\line_width)) > (\max_immed) + .set _reps, 2 + .else + .set _reps, 4 + .endif + + __loopi \ar, \at, \size, (_reps << (\line_width)) + .set _index, 0 + .rep _reps + \insn \ar, _index << (\line_width) + .set _index, _index + 1 + .endr + __endla \ar, \at, _reps << (\line_width) + + .endm + - __loopi \ar, \at, \size, (4 << (\line_width)) - \insn \ar, 0 << (\line_width) - \insn \ar, 1 << (\line_width) - \insn \ar, 2 << (\line_width) - \insn \ar, 3 << (\line_width) - __endla \ar, \at, 4 << (\line_width) + .macro __loop_cache_all ar at insn size line_width max_immed + + movi \ar, 0 + __loop_cache_unroll \ar, \at, \insn, \size, \line_width, \max_immed .endm @@ -57,14 +73,9 @@ .endm - .macro __loop_cache_page ar at insn line_width + .macro __loop_cache_page ar at insn line_width max_immed - __loopi \ar, \at, PAGE_SIZE, 4 << (\line_width) - \insn \ar, 0 << (\line_width) - \insn \ar, 1 << (\line_width) - \insn \ar, 2 << (\line_width) - \insn \ar, 3 << (\line_width) - __endla \ar, \at, 4 << (\line_width) + __loop_cache_unroll \ar, \at, \insn, PAGE_SIZE, \line_width, \max_immed .endm @@ -72,7 +83,8 @@ .macro ___unlock_dcache_all ar at #if XCHAL_DCACHE_LINE_LOCKABLE && XCHAL_DCACHE_SIZE - __loop_cache_all \ar \at diu XCHAL_DCACHE_SIZE XCHAL_DCACHE_LINEWIDTH + __loop_cache_all \ar \at diu XCHAL_DCACHE_SIZE \ + XCHAL_DCACHE_LINEWIDTH 240 #endif .endm @@ -81,7 +93,8 @@ .macro ___unlock_icache_all ar at #if XCHAL_ICACHE_LINE_LOCKABLE && XCHAL_ICACHE_SIZE - __loop_cache_all \ar \at iiu XCHAL_ICACHE_SIZE XCHAL_ICACHE_LINEWIDTH + __loop_cache_all \ar \at iiu XCHAL_ICACHE_SIZE \ + XCHAL_ICACHE_LINEWIDTH 240 #endif .endm @@ -90,7 +103,8 @@ .macro ___flush_invalidate_dcache_all ar at #if XCHAL_DCACHE_SIZE - __loop_cache_all \ar \at diwbi XCHAL_DCACHE_SIZE XCHAL_DCACHE_LINEWIDTH + __loop_cache_all \ar \at diwbi XCHAL_DCACHE_SIZE \ + XCHAL_DCACHE_LINEWIDTH 240 #endif .endm @@ -99,7 +113,8 @@ .macro ___flush_dcache_all ar at #if XCHAL_DCACHE_SIZE - __loop_cache_all \ar \at diwb XCHAL_DCACHE_SIZE XCHAL_DCACHE_LINEWIDTH + __loop_cache_all \ar \at diwb XCHAL_DCACHE_SIZE \ + XCHAL_DCACHE_LINEWIDTH 240 #endif .endm @@ -108,8 +123,8 @@ .macro ___invalidate_dcache_all ar at #if XCHAL_DCACHE_SIZE - __loop_cache_all \ar \at dii __stringify(DCACHE_WAY_SIZE) \ - XCHAL_DCACHE_LINEWIDTH + __loop_cache_all \ar \at dii XCHAL_DCACHE_SIZE \ + XCHAL_DCACHE_LINEWIDTH 1020 #endif .endm @@ -118,8 +133,8 @@ .macro ___invalidate_icache_all ar at #if XCHAL_ICACHE_SIZE - __loop_cache_all \ar \at iii __stringify(ICACHE_WAY_SIZE) \ - XCHAL_ICACHE_LINEWIDTH + __loop_cache_all \ar \at iii XCHAL_ICACHE_SIZE \ + XCHAL_ICACHE_LINEWIDTH 1020 #endif .endm @@ -166,7 +181,7 @@ .macro ___flush_invalidate_dcache_page ar as #if XCHAL_DCACHE_SIZE - __loop_cache_page \ar \as dhwbi XCHAL_DCACHE_LINEWIDTH + __loop_cache_page \ar \as dhwbi XCHAL_DCACHE_LINEWIDTH 1020 #endif .endm @@ -175,7 +190,7 @@ .macro ___flush_dcache_page ar as #if XCHAL_DCACHE_SIZE - __loop_cache_page \ar \as dhwb XCHAL_DCACHE_LINEWIDTH + __loop_cache_page \ar \as dhwb XCHAL_DCACHE_LINEWIDTH 1020 #endif .endm @@ -184,7 +199,7 @@ .macro ___invalidate_dcache_page ar as #if XCHAL_DCACHE_SIZE - __loop_cache_page \ar \as dhi XCHAL_DCACHE_LINEWIDTH + __loop_cache_page \ar \as dhi XCHAL_DCACHE_LINEWIDTH 1020 #endif .endm @@ -193,7 +208,7 @@ .macro ___invalidate_icache_page ar as #if XCHAL_ICACHE_SIZE - __loop_cache_page \ar \as ihi XCHAL_ICACHE_LINEWIDTH + __loop_cache_page \ar \as ihi XCHAL_ICACHE_LINEWIDTH 1020 #endif .endm diff --git a/arch/xtensa/platforms/iss/setup.c b/arch/xtensa/platforms/iss/setup.c index f4bbb28026f8be3006890fe236989db791c79e1d..58709e89a8ed1f41ed7acaad204d4d91e973386a 100644 --- a/arch/xtensa/platforms/iss/setup.c +++ b/arch/xtensa/platforms/iss/setup.c @@ -78,23 +78,28 @@ static struct notifier_block iss_panic_block = { void __init platform_setup(char **p_cmdline) { + static void *argv[COMMAND_LINE_SIZE / sizeof(void *)] __initdata; + static char cmdline[COMMAND_LINE_SIZE] __initdata; int argc = simc_argc(); int argv_size = simc_argv_size(); if (argc > 1) { - void **argv = alloc_bootmem(argv_size); - char *cmdline = alloc_bootmem(argv_size); - int i; + if (argv_size > sizeof(argv)) { + pr_err("%s: command line too long: argv_size = %d\n", + __func__, argv_size); + } else { + int i; - cmdline[0] = 0; - simc_argv((void *)argv); + cmdline[0] = 0; + simc_argv((void *)argv); - for (i = 1; i < argc; ++i) { - if (i > 1) - strcat(cmdline, " "); - strcat(cmdline, argv[i]); + for (i = 1; i < argc; ++i) { + if (i > 1) + strcat(cmdline, " "); + strcat(cmdline, argv[i]); + } + *p_cmdline = cmdline; } - *p_cmdline = cmdline; } atomic_notifier_chain_register(&panic_notifier_list, &iss_panic_block); diff --git a/block/bfq-cgroup.c b/block/bfq-cgroup.c index 5d53e504acae58d02fa3d8c0b5cef4b625e758aa..afbbe5750a1f85b635e7cd9a903314c0729c26d4 100644 --- a/block/bfq-cgroup.c +++ b/block/bfq-cgroup.c @@ -224,9 +224,9 @@ static void bfqg_and_blkg_get(struct bfq_group *bfqg) void bfqg_and_blkg_put(struct bfq_group *bfqg) { - bfqg_put(bfqg); - blkg_put(bfqg_to_blkg(bfqg)); + + bfqg_put(bfqg); } void bfqg_stats_update_io_add(struct bfq_group *bfqg, struct bfq_queue *bfqq, @@ -887,7 +887,8 @@ static ssize_t bfq_io_set_weight(struct kernfs_open_file *of, if (ret) return ret; - return bfq_io_set_weight_legacy(of_css(of), NULL, weight); + ret = bfq_io_set_weight_legacy(of_css(of), NULL, weight); + return ret ?: nbytes; } static int bfqg_print_stat(struct seq_file *sf, void *v) diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c index 4a4b7d3c909a846ac66144cedca8fa891e09080d..3b44bd28fc4521e40c787c5bd7957443fcb506c5 100644 --- a/block/bfq-iosched.c +++ b/block/bfq-iosched.c @@ -1203,6 +1203,24 @@ static unsigned int bfq_wr_duration(struct bfq_data *bfqd) return dur; } +/* + * Return the farthest future time instant according to jiffies + * macros. + */ +static unsigned long bfq_greatest_from_now(void) +{ + return jiffies + MAX_JIFFY_OFFSET; +} + +/* + * Return the farthest past time instant according to jiffies + * macros. + */ +static unsigned long bfq_smallest_from_now(void) +{ + return jiffies - MAX_JIFFY_OFFSET; +} + static void bfq_update_bfqq_wr_on_rq_arrival(struct bfq_data *bfqd, struct bfq_queue *bfqq, unsigned int old_wr_coeff, @@ -1217,7 +1235,19 @@ static void bfq_update_bfqq_wr_on_rq_arrival(struct bfq_data *bfqd, bfqq->wr_coeff = bfqd->bfq_wr_coeff; bfqq->wr_cur_max_time = bfq_wr_duration(bfqd); } else { - bfqq->wr_start_at_switch_to_srt = jiffies; + /* + * No interactive weight raising in progress + * here: assign minus infinity to + * wr_start_at_switch_to_srt, to make sure + * that, at the end of the soft-real-time + * weight raising periods that is starting + * now, no interactive weight-raising period + * may be wrongly considered as still in + * progress (and thus actually started by + * mistake). + */ + bfqq->wr_start_at_switch_to_srt = + bfq_smallest_from_now(); bfqq->wr_coeff = bfqd->bfq_wr_coeff * BFQ_SOFTRT_WEIGHT_FACTOR; bfqq->wr_cur_max_time = @@ -2896,24 +2926,6 @@ static unsigned long bfq_bfqq_softrt_next_start(struct bfq_data *bfqd, jiffies + nsecs_to_jiffies(bfqq->bfqd->bfq_slice_idle) + 4); } -/* - * Return the farthest future time instant according to jiffies - * macros. - */ -static unsigned long bfq_greatest_from_now(void) -{ - return jiffies + MAX_JIFFY_OFFSET; -} - -/* - * Return the farthest past time instant according to jiffies - * macros. - */ -static unsigned long bfq_smallest_from_now(void) -{ - return jiffies - MAX_JIFFY_OFFSET; -} - /** * bfq_bfqq_expire - expire a queue. * @bfqd: device owning the queue. diff --git a/block/bio.c b/block/bio.c index 3a63aba1509dcbc36f3d4e16e10eebe40dc04ed6..dc247bbbe704d31617c33a3b16eeca366e2cd429 100644 --- a/block/bio.c +++ b/block/bio.c @@ -156,7 +156,7 @@ static void bio_put_slab(struct bio_set *bs) unsigned int bvec_nr_vecs(unsigned short idx) { - return bvec_slabs[idx].nr_vecs; + return bvec_slabs[--idx].nr_vecs; } void bvec_free(mempool_t *pool, struct bio_vec *bv, unsigned int idx) @@ -617,7 +617,6 @@ void __bio_clone_fast(struct bio *bio, struct bio *bio_src) bio->bi_write_hint = bio_src->bi_write_hint; bio->bi_iter = bio_src->bi_iter; bio->bi_io_vec = bio_src->bi_io_vec; - bio->bi_dio_inode = bio_src->bi_dio_inode; bio_clone_crypt_key(bio, bio_src); bio_clone_blkcg_association(bio, bio_src); } diff --git a/block/blk-core.c b/block/blk-core.c index d21f176246b246acba0075087e7bebb7501c51e8..e57aed3f621147648dc3c2fa6c7fa6411ab7bcb7 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -671,9 +671,13 @@ void blk_cleanup_queue(struct request_queue *q) * make sure all in-progress dispatch are completed because * blk_freeze_queue() can only complete all requests, and * dispatch may still be in-progress since we dispatch requests - * from more than one contexts + * from more than one contexts. + * + * No need to quiesce queue if it isn't initialized yet since + * blk_freeze_queue() should be enough for cases of passthrough + * request. */ - if (q->mq_ops) + if (q->mq_ops && blk_queue_init_done(q)) blk_mq_quiesce_queue(q); /* for synchronous bio-based driver finish in-flight integrity i/o */ @@ -1027,6 +1031,7 @@ int blk_init_allocated_queue(struct request_queue *q) q->exit_rq_fn(q, q->fq->flush_rq); out_free_flush_queue: blk_free_flush_queue(q->fq); + q->fq = NULL; return -ENOMEM; } EXPORT_SYMBOL(blk_init_allocated_queue); @@ -1650,7 +1655,9 @@ bool bio_attempt_front_merge(struct request_queue *q, struct request *req, bio->bi_next = req->bio; req->bio = bio; +#ifdef CONFIG_PFK WARN_ON(req->__dun || bio->bi_iter.bi_dun); +#endif req->__sector = bio->bi_iter.bi_sector; req->__data_len += bio->bi_iter.bi_size; req->ioprio = ioprio_best(req->ioprio, bio_prio(bio)); @@ -1800,7 +1807,9 @@ void blk_init_request_from_bio(struct request *req, struct bio *bio) else req->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, 0); req->write_hint = bio->bi_write_hint; +#ifdef CONFIG_PFK req->__dun = bio->bi_iter.bi_dun; +#endif blk_rq_bio_prep(req->q, req, bio); } EXPORT_SYMBOL_GPL(blk_init_request_from_bio); @@ -2790,8 +2799,10 @@ bool blk_update_request(struct request *req, blk_status_t error, /* update sector only for requests with clear definition of sector */ if (!blk_rq_is_passthrough(req)) { req->__sector += total_bytes >> 9; +#ifdef CONFIG_PFK if (req->__dun) req->__dun += total_bytes >> 12; +#endif } /* mixed attributes always follow the first bio */ @@ -3155,7 +3166,9 @@ static void __blk_rq_prep_clone(struct request *dst, struct request *src) { dst->cpu = src->cpu; dst->__sector = blk_rq_pos(src); +#ifdef CONFIG_PFK dst->__dun = blk_rq_dun(src); +#endif dst->__data_len = blk_rq_bytes(src); if (src->rq_flags & RQF_SPECIAL_PAYLOAD) { dst->rq_flags |= RQF_SPECIAL_PAYLOAD; @@ -3468,9 +3481,11 @@ EXPORT_SYMBOL(blk_finish_plug); */ void blk_pm_runtime_init(struct request_queue *q, struct device *dev) { - /* not support for RQF_PM and ->rpm_status in blk-mq yet */ - if (q->mq_ops) + /* Don't enable runtime PM for blk-mq until it is ready */ + if (q->mq_ops) { + pm_runtime_disable(dev); return; + } q->dev = dev; q->rpm_status = RPM_ACTIVE; diff --git a/block/blk-merge.c b/block/blk-merge.c index 390f3464322d05de31583e27e8a2a9821afdfa46..079a3cf533f952dd143f3f54a32658e3791a0ba0 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -845,8 +845,10 @@ bool blk_rq_merge_ok(struct request *rq, struct bio *bio) enum elv_merge blk_try_merge(struct request *rq, struct bio *bio) { +#ifdef CONFIG_PFK if (blk_rq_dun(rq) || bio_dun(bio)) return ELEVATOR_NO_MERGE; +#endif if (req_op(rq) == REQ_OP_DISCARD && queue_max_discard_segments(rq->q) > 1) return ELEVATOR_DISCARD_MERGE; diff --git a/block/blk-mq-sched.c b/block/blk-mq-sched.c index eca011fdfa0ede407443c2de9c1e7d45787f4313..ae5d8f10a27c59a957911dd66fa9b68a7fc5c6e6 100644 --- a/block/blk-mq-sched.c +++ b/block/blk-mq-sched.c @@ -236,7 +236,8 @@ bool __blk_mq_sched_bio_merge(struct request_queue *q, struct bio *bio) return e->type->ops.mq.bio_merge(hctx, bio); } - if (hctx->flags & BLK_MQ_F_SHOULD_MERGE) { + if ((hctx->flags & BLK_MQ_F_SHOULD_MERGE) && + !list_empty_careful(&ctx->rq_list)) { /* default per sw-queue merge */ spin_lock(&ctx->lock); ret = blk_mq_attempt_merge(q, ctx, bio); diff --git a/block/blk-mq-tag.c b/block/blk-mq-tag.c index 6714507aa6c75b716d34a53c708952bf5d0ae619..3d2ab65d2dd15a012d3ff1efb71ad5b5aca6ddd5 100644 --- a/block/blk-mq-tag.c +++ b/block/blk-mq-tag.c @@ -416,8 +416,6 @@ int blk_mq_tag_update_depth(struct blk_mq_hw_ctx *hctx, if (tdepth <= tags->nr_reserved_tags) return -EINVAL; - tdepth -= tags->nr_reserved_tags; - /* * If we are allowed to grow beyond the original size, allocate * a new set of tags before freeing the old one. @@ -437,7 +435,8 @@ int blk_mq_tag_update_depth(struct blk_mq_hw_ctx *hctx, if (tdepth > 16 * BLKDEV_MAX_RQ) return -EINVAL; - new = blk_mq_alloc_rq_map(set, hctx->queue_num, tdepth, 0); + new = blk_mq_alloc_rq_map(set, hctx->queue_num, tdepth, + tags->nr_reserved_tags); if (!new) return -ENOMEM; ret = blk_mq_alloc_rqs(set, new, hctx->queue_num, tdepth); @@ -454,7 +453,8 @@ int blk_mq_tag_update_depth(struct blk_mq_hw_ctx *hctx, * Don't need (or can't) update reserved tags here, they * remain static and should never need resizing. */ - sbitmap_queue_resize(&tags->bitmap_tags, tdepth); + sbitmap_queue_resize(&tags->bitmap_tags, + tdepth - tags->nr_reserved_tags); } return 0; diff --git a/block/blk-mq.c b/block/blk-mq.c index 49979c095f31c4885c020d469a068738fa30fa15..eac4448047366bb60db76788833f6e5b977dd467 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -1512,7 +1512,7 @@ void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule) BUG_ON(!rq->q); if (rq->mq_ctx != this_ctx) { if (this_ctx) { - trace_block_unplug(this_q, depth, from_schedule); + trace_block_unplug(this_q, depth, !from_schedule); blk_mq_sched_insert_requests(this_q, this_ctx, &ctx_list, from_schedule); @@ -1532,7 +1532,7 @@ void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule) * on 'ctx_list'. Do those. */ if (this_ctx) { - trace_block_unplug(this_q, depth, from_schedule); + trace_block_unplug(this_q, depth, !from_schedule); blk_mq_sched_insert_requests(this_q, this_ctx, &ctx_list, from_schedule); } diff --git a/block/blk-settings.c b/block/blk-settings.c index 8559e9563c5255f114309e95a9d09b71550d0af2..474b0b95fcd16e0069639bfc264637a601703a99 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -128,7 +128,7 @@ void blk_set_stacking_limits(struct queue_limits *lim) /* Inherit limits from component devices */ lim->max_segments = USHRT_MAX; - lim->max_discard_segments = 1; + lim->max_discard_segments = USHRT_MAX; lim->max_hw_sectors = UINT_MAX; lim->max_segment_size = UINT_MAX; lim->max_sectors = UINT_MAX; diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 9f342ef1ad426fa7d60e00fffeb313409cbbb3f4..9c4f1c496c90c9af5d59bb94be5c24fe48c1debb 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -4741,12 +4741,13 @@ USEC_SHOW_FUNCTION(cfq_target_latency_us_show, cfqd->cfq_target_latency); static ssize_t __FUNC(struct elevator_queue *e, const char *page, size_t count) \ { \ struct cfq_data *cfqd = e->elevator_data; \ - unsigned int __data; \ + unsigned int __data, __min = (MIN), __max = (MAX); \ + \ cfq_var_store(&__data, (page)); \ - if (__data < (MIN)) \ - __data = (MIN); \ - else if (__data > (MAX)) \ - __data = (MAX); \ + if (__data < __min) \ + __data = __min; \ + else if (__data > __max) \ + __data = __max; \ if (__CONV) \ *(__PTR) = (u64)__data * NSEC_PER_MSEC; \ else \ @@ -4775,12 +4776,13 @@ STORE_FUNCTION(cfq_target_latency_store, &cfqd->cfq_target_latency, 1, UINT_MAX, static ssize_t __FUNC(struct elevator_queue *e, const char *page, size_t count) \ { \ struct cfq_data *cfqd = e->elevator_data; \ - unsigned int __data; \ + unsigned int __data, __min = (MIN), __max = (MAX); \ + \ cfq_var_store(&__data, (page)); \ - if (__data < (MIN)) \ - __data = (MIN); \ - else if (__data > (MAX)) \ - __data = (MAX); \ + if (__data < __min) \ + __data = __min; \ + else if (__data > __max) \ + __data = __max; \ *(__PTR) = (u64)__data * NSEC_PER_USEC; \ return count; \ } diff --git a/block/partitions/aix.c b/block/partitions/aix.c index 007f95eea0e1a9b6b79751ce6f109d151daa12f4..903f3ed175d0263344fe33ecbe19dfaeffcb202e 100644 --- a/block/partitions/aix.c +++ b/block/partitions/aix.c @@ -178,7 +178,7 @@ int aix_partition(struct parsed_partitions *state) u32 vgda_sector = 0; u32 vgda_len = 0; int numlvs = 0; - struct pvd *pvd; + struct pvd *pvd = NULL; struct lv_info { unsigned short pps_per_lv; unsigned short pps_found; @@ -232,10 +232,11 @@ int aix_partition(struct parsed_partitions *state) if (lvip[i].pps_per_lv) foundlvs += 1; } + /* pvd loops depend on n[].name and lvip[].pps_per_lv */ + pvd = alloc_pvd(state, vgda_sector + 17); } put_dev_sector(sect); } - pvd = alloc_pvd(state, vgda_sector + 17); if (pvd) { int numpps = be16_to_cpu(pvd->pp_count); int psn_part1 = be32_to_cpu(pvd->psn_part1); @@ -282,10 +283,14 @@ int aix_partition(struct parsed_partitions *state) next_lp_ix += 1; } for (i = 0; i < state->limit; i += 1) - if (lvip[i].pps_found && !lvip[i].lv_is_contiguous) + if (lvip[i].pps_found && !lvip[i].lv_is_contiguous) { + char tmp[sizeof(n[i].name) + 1]; // null char + + snprintf(tmp, sizeof(tmp), "%s", n[i].name); pr_warn("partition %s (%u pp's found) is " "not contiguous\n", - n[i].name, lvip[i].pps_found); + tmp, lvip[i].pps_found); + } kfree(pvd); } kfree(n); diff --git a/block/sed-opal.c b/block/sed-opal.c index 9ed51d0c6b1d171fc2eab785ef854b64f93721fe..4f5e70d4abc3cd282db163c6614b24c31a4c0fe5 100644 --- a/block/sed-opal.c +++ b/block/sed-opal.c @@ -877,7 +877,7 @@ static size_t response_get_string(const struct parsed_resp *resp, int n, return 0; } - if (n > resp->num) { + if (n >= resp->num) { pr_debug("Response has %d tokens. Can't access %d\n", resp->num, n); return 0; @@ -899,7 +899,7 @@ static u64 response_get_u64(const struct parsed_resp *resp, int n) return 0; } - if (n > resp->num) { + if (n >= resp->num) { pr_debug("Response has %d tokens. Can't access %d\n", resp->num, n); return 0; diff --git a/certs/system_keyring.c b/certs/system_keyring.c index 0e1ea235c12a31363234964bac2482d4836a4928..4ba922ff3db6ba0c78ba040bc63a665da00af28f 100644 --- a/certs/system_keyring.c +++ b/certs/system_keyring.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -230,7 +231,7 @@ int verify_pkcs7_signature(const void *data, size_t len, if (!trusted_keys) { trusted_keys = builtin_trusted_keys; - } else if (trusted_keys == (void *)1UL) { + } else if (trusted_keys == VERIFY_USE_SECONDARY_KEYRING) { #ifdef CONFIG_SECONDARY_TRUSTED_KEYRING trusted_keys = secondary_trusted_keys; #else diff --git a/crypto/Makefile b/crypto/Makefile index 2ae78fb2a39016dc11124c3bc2ea175ac6442e1f..59220c2264e1ba30012731fa99873a9d7193afcb 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -98,7 +98,7 @@ obj-$(CONFIG_CRYPTO_TWOFISH_COMMON) += twofish_common.o obj-$(CONFIG_CRYPTO_SERPENT) += serpent_generic.o CFLAGS_serpent_generic.o := $(call cc-option,-fsched-pressure) # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79149 obj-$(CONFIG_CRYPTO_AES) += aes_generic.o -CFLAGS_aes_generic.o := $(call cc-ifversion, -ge, 0701, -Os) # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83356 +CFLAGS_aes_generic.o := $(call cc-option,-fno-code-hoisting) # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83356 obj-$(CONFIG_CRYPTO_AES_TI) += aes_ti.o obj-$(CONFIG_CRYPTO_CAMELLIA) += camellia_generic.o obj-$(CONFIG_CRYPTO_CAST_COMMON) += cast_common.o diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c index d880a489715976fef528cfc7544956d1ce761b52..8882e90e868eade5b77fc310fb5238dd322e9f03 100644 --- a/crypto/ablkcipher.c +++ b/crypto/ablkcipher.c @@ -71,11 +71,9 @@ static inline u8 *ablkcipher_get_spot(u8 *start, unsigned int len) return max(start, end_page); } -static inline unsigned int ablkcipher_done_slow(struct ablkcipher_walk *walk, - unsigned int bsize) +static inline void ablkcipher_done_slow(struct ablkcipher_walk *walk, + unsigned int n) { - unsigned int n = bsize; - for (;;) { unsigned int len_this_page = scatterwalk_pagelen(&walk->out); @@ -87,17 +85,13 @@ static inline unsigned int ablkcipher_done_slow(struct ablkcipher_walk *walk, n -= len_this_page; scatterwalk_start(&walk->out, sg_next(walk->out.sg)); } - - return bsize; } -static inline unsigned int ablkcipher_done_fast(struct ablkcipher_walk *walk, - unsigned int n) +static inline void ablkcipher_done_fast(struct ablkcipher_walk *walk, + unsigned int n) { scatterwalk_advance(&walk->in, n); scatterwalk_advance(&walk->out, n); - - return n; } static int ablkcipher_walk_next(struct ablkcipher_request *req, @@ -107,39 +101,40 @@ int ablkcipher_walk_done(struct ablkcipher_request *req, struct ablkcipher_walk *walk, int err) { struct crypto_tfm *tfm = req->base.tfm; - unsigned int nbytes = 0; + unsigned int n; /* bytes processed */ + bool more; - if (likely(err >= 0)) { - unsigned int n = walk->nbytes - err; + if (unlikely(err < 0)) + goto finish; - if (likely(!(walk->flags & ABLKCIPHER_WALK_SLOW))) - n = ablkcipher_done_fast(walk, n); - else if (WARN_ON(err)) { - err = -EINVAL; - goto err; - } else - n = ablkcipher_done_slow(walk, n); + n = walk->nbytes - err; + walk->total -= n; + more = (walk->total != 0); - nbytes = walk->total - n; - err = 0; + if (likely(!(walk->flags & ABLKCIPHER_WALK_SLOW))) { + ablkcipher_done_fast(walk, n); + } else { + if (WARN_ON(err)) { + /* unexpected case; didn't process all bytes */ + err = -EINVAL; + goto finish; + } + ablkcipher_done_slow(walk, n); } - scatterwalk_done(&walk->in, 0, nbytes); - scatterwalk_done(&walk->out, 1, nbytes); - -err: - walk->total = nbytes; - walk->nbytes = nbytes; + scatterwalk_done(&walk->in, 0, more); + scatterwalk_done(&walk->out, 1, more); - if (nbytes) { + if (more) { crypto_yield(req->base.flags); return ablkcipher_walk_next(req, walk); } - + err = 0; +finish: + walk->nbytes = 0; if (walk->iv != req->info) memcpy(req->info, walk->iv, tfm->crt_ablkcipher.ivsize); kfree(walk->iv_buffer); - return err; } EXPORT_SYMBOL_GPL(ablkcipher_walk_done); @@ -373,6 +368,7 @@ static int crypto_ablkcipher_report(struct sk_buff *skb, struct crypto_alg *alg) strncpy(rblkcipher.type, "ablkcipher", sizeof(rblkcipher.type)); strncpy(rblkcipher.geniv, alg->cra_ablkcipher.geniv ?: "", sizeof(rblkcipher.geniv)); + rblkcipher.geniv[sizeof(rblkcipher.geniv) - 1] = '\0'; rblkcipher.blocksize = alg->cra_blocksize; rblkcipher.min_keysize = alg->cra_ablkcipher.min_keysize; @@ -447,6 +443,7 @@ static int crypto_givcipher_report(struct sk_buff *skb, struct crypto_alg *alg) strncpy(rblkcipher.type, "givcipher", sizeof(rblkcipher.type)); strncpy(rblkcipher.geniv, alg->cra_ablkcipher.geniv ?: "", sizeof(rblkcipher.geniv)); + rblkcipher.geniv[sizeof(rblkcipher.geniv) - 1] = '\0'; rblkcipher.blocksize = alg->cra_blocksize; rblkcipher.min_keysize = alg->cra_ablkcipher.min_keysize; diff --git a/crypto/api.c b/crypto/api.c index 2a2479d168aacbe3e31799a2c713614b71e6805b..ff7a7852bb17acc90535be965727f42a2a9ef7e4 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -216,7 +216,7 @@ struct crypto_alg *crypto_larval_lookup(const char *name, u32 type, u32 mask) mask &= ~(CRYPTO_ALG_LARVAL | CRYPTO_ALG_DEAD); alg = crypto_alg_lookup(name, type, mask); - if (!alg) { + if (!alg && !(mask & CRYPTO_NOLOAD)) { request_module("crypto-%s", name); if (!((type ^ CRYPTO_ALG_NEED_FALLBACK) & mask & diff --git a/crypto/asymmetric_keys/pkcs7_key_type.c b/crypto/asymmetric_keys/pkcs7_key_type.c index 1063b644efcdb3b2cbde33483207b7fc06e4eb5b..b2aa925a84bc512cabe5446c5c65e769fac1ff96 100644 --- a/crypto/asymmetric_keys/pkcs7_key_type.c +++ b/crypto/asymmetric_keys/pkcs7_key_type.c @@ -62,7 +62,7 @@ static int pkcs7_preparse(struct key_preparsed_payload *prep) return verify_pkcs7_signature(NULL, 0, prep->data, prep->datalen, - (void *)1UL, usage, + VERIFY_USE_SECONDARY_KEYRING, usage, pkcs7_view_content, prep); } diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c index 6c43a0a17a5514b46f9300e21ded357defb39d50..830821f234d2805e9c3ecc8348a06ed0e6f47820 100644 --- a/crypto/blkcipher.c +++ b/crypto/blkcipher.c @@ -71,19 +71,18 @@ static inline u8 *blkcipher_get_spot(u8 *start, unsigned int len) return max(start, end_page); } -static inline unsigned int blkcipher_done_slow(struct blkcipher_walk *walk, - unsigned int bsize) +static inline void blkcipher_done_slow(struct blkcipher_walk *walk, + unsigned int bsize) { u8 *addr; addr = (u8 *)ALIGN((unsigned long)walk->buffer, walk->alignmask + 1); addr = blkcipher_get_spot(addr, bsize); scatterwalk_copychunks(addr, &walk->out, bsize, 1); - return bsize; } -static inline unsigned int blkcipher_done_fast(struct blkcipher_walk *walk, - unsigned int n) +static inline void blkcipher_done_fast(struct blkcipher_walk *walk, + unsigned int n) { if (walk->flags & BLKCIPHER_WALK_COPY) { blkcipher_map_dst(walk); @@ -97,49 +96,48 @@ static inline unsigned int blkcipher_done_fast(struct blkcipher_walk *walk, scatterwalk_advance(&walk->in, n); scatterwalk_advance(&walk->out, n); - - return n; } int blkcipher_walk_done(struct blkcipher_desc *desc, struct blkcipher_walk *walk, int err) { - unsigned int nbytes = 0; + unsigned int n; /* bytes processed */ + bool more; - if (likely(err >= 0)) { - unsigned int n = walk->nbytes - err; + if (unlikely(err < 0)) + goto finish; - if (likely(!(walk->flags & BLKCIPHER_WALK_SLOW))) - n = blkcipher_done_fast(walk, n); - else if (WARN_ON(err)) { - err = -EINVAL; - goto err; - } else - n = blkcipher_done_slow(walk, n); + n = walk->nbytes - err; + walk->total -= n; + more = (walk->total != 0); - nbytes = walk->total - n; - err = 0; + if (likely(!(walk->flags & BLKCIPHER_WALK_SLOW))) { + blkcipher_done_fast(walk, n); + } else { + if (WARN_ON(err)) { + /* unexpected case; didn't process all bytes */ + err = -EINVAL; + goto finish; + } + blkcipher_done_slow(walk, n); } - scatterwalk_done(&walk->in, 0, nbytes); - scatterwalk_done(&walk->out, 1, nbytes); + scatterwalk_done(&walk->in, 0, more); + scatterwalk_done(&walk->out, 1, more); -err: - walk->total = nbytes; - walk->nbytes = nbytes; - - if (nbytes) { + if (more) { crypto_yield(desc->flags); return blkcipher_walk_next(desc, walk); } - + err = 0; +finish: + walk->nbytes = 0; if (walk->iv != desc->info) memcpy(desc->info, walk->iv, walk->ivsize); if (walk->buffer != walk->page) kfree(walk->buffer); if (walk->page) free_page((unsigned long)walk->page); - return err; } EXPORT_SYMBOL_GPL(blkcipher_walk_done); @@ -513,6 +511,7 @@ static int crypto_blkcipher_report(struct sk_buff *skb, struct crypto_alg *alg) strncpy(rblkcipher.type, "blkcipher", sizeof(rblkcipher.type)); strncpy(rblkcipher.geniv, alg->cra_blkcipher.geniv ?: "", sizeof(rblkcipher.geniv)); + rblkcipher.geniv[sizeof(rblkcipher.geniv) - 1] = '\0'; rblkcipher.blocksize = alg->cra_blocksize; rblkcipher.min_keysize = alg->cra_blkcipher.min_keysize; diff --git a/crypto/skcipher.c b/crypto/skcipher.c index 11af5fd6a443570550e1dac5b0a429b2cae801b1..e319421a32e7de4fabadddf116f64eeea790a113 100644 --- a/crypto/skcipher.c +++ b/crypto/skcipher.c @@ -95,7 +95,7 @@ static inline u8 *skcipher_get_spot(u8 *start, unsigned int len) return max(start, end_page); } -static int skcipher_done_slow(struct skcipher_walk *walk, unsigned int bsize) +static void skcipher_done_slow(struct skcipher_walk *walk, unsigned int bsize) { u8 *addr; @@ -103,23 +103,24 @@ static int skcipher_done_slow(struct skcipher_walk *walk, unsigned int bsize) addr = skcipher_get_spot(addr, bsize); scatterwalk_copychunks(addr, &walk->out, bsize, (walk->flags & SKCIPHER_WALK_PHYS) ? 2 : 1); - return 0; } int skcipher_walk_done(struct skcipher_walk *walk, int err) { - unsigned int n = walk->nbytes - err; - unsigned int nbytes; + unsigned int n; /* bytes processed */ + bool more; + + if (unlikely(err < 0)) + goto finish; - nbytes = walk->total - n; + n = walk->nbytes - err; + walk->total -= n; + more = (walk->total != 0); - if (unlikely(err < 0)) { - nbytes = 0; - n = 0; - } else if (likely(!(walk->flags & (SKCIPHER_WALK_PHYS | - SKCIPHER_WALK_SLOW | - SKCIPHER_WALK_COPY | - SKCIPHER_WALK_DIFF)))) { + if (likely(!(walk->flags & (SKCIPHER_WALK_PHYS | + SKCIPHER_WALK_SLOW | + SKCIPHER_WALK_COPY | + SKCIPHER_WALK_DIFF)))) { unmap_src: skcipher_unmap_src(walk); } else if (walk->flags & SKCIPHER_WALK_DIFF) { @@ -131,28 +132,28 @@ int skcipher_walk_done(struct skcipher_walk *walk, int err) skcipher_unmap_dst(walk); } else if (unlikely(walk->flags & SKCIPHER_WALK_SLOW)) { if (WARN_ON(err)) { + /* unexpected case; didn't process all bytes */ err = -EINVAL; - nbytes = 0; - } else - n = skcipher_done_slow(walk, n); + goto finish; + } + skcipher_done_slow(walk, n); + goto already_advanced; } - if (err > 0) - err = 0; - - walk->total = nbytes; - walk->nbytes = nbytes; - scatterwalk_advance(&walk->in, n); scatterwalk_advance(&walk->out, n); - scatterwalk_done(&walk->in, 0, nbytes); - scatterwalk_done(&walk->out, 1, nbytes); +already_advanced: + scatterwalk_done(&walk->in, 0, more); + scatterwalk_done(&walk->out, 1, more); - if (nbytes) { + if (more) { crypto_yield(walk->flags & SKCIPHER_WALK_SLEEP ? CRYPTO_TFM_REQ_MAY_SLEEP : 0); return skcipher_walk_next(walk); } + err = 0; +finish: + walk->nbytes = 0; /* Short-circuit for the common/fast path. */ if (!((unsigned long)walk->buffer | (unsigned long)walk->page)) @@ -399,7 +400,7 @@ static int skcipher_copy_iv(struct skcipher_walk *walk) unsigned size; u8 *iv; - aligned_bs = ALIGN(bs, alignmask); + aligned_bs = ALIGN(bs, alignmask + 1); /* Minimum size to align buffer by alignmask. */ size = alignmask & ~a; diff --git a/crypto/vmac.c b/crypto/vmac.c index df76a816cfb22f68ac173d3ef01e2e2f9e166c72..bb2fc787d61568d3c0a871f1fc2e04cfc0732437 100644 --- a/crypto/vmac.c +++ b/crypto/vmac.c @@ -1,6 +1,10 @@ /* - * Modified to interface to the Linux kernel + * VMAC: Message Authentication Code using Universal Hashing + * + * Reference: https://tools.ietf.org/html/draft-krovetz-vmac-01 + * * Copyright (c) 2009, Intel Corporation. + * Copyright (c) 2018, Google Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -16,14 +20,15 @@ * Place - Suite 330, Boston, MA 02111-1307 USA. */ -/* -------------------------------------------------------------------------- - * VMAC and VHASH Implementation by Ted Krovetz (tdk@acm.org) and Wei Dai. - * This implementation is herby placed in the public domain. - * The authors offers no warranty. Use at your own risk. - * Please send bug reports to the authors. - * Last modified: 17 APR 08, 1700 PDT - * ----------------------------------------------------------------------- */ +/* + * Derived from: + * VMAC and VHASH Implementation by Ted Krovetz (tdk@acm.org) and Wei Dai. + * This implementation is herby placed in the public domain. + * The authors offers no warranty. Use at your own risk. + * Last modified: 17 APR 08, 1700 PDT + */ +#include #include #include #include @@ -31,9 +36,35 @@ #include #include #include -#include #include +/* + * User definable settings. + */ +#define VMAC_TAG_LEN 64 +#define VMAC_KEY_SIZE 128/* Must be 128, 192 or 256 */ +#define VMAC_KEY_LEN (VMAC_KEY_SIZE/8) +#define VMAC_NHBYTES 128/* Must 2^i for any 3 < i < 13 Standard = 128*/ + +/* per-transform (per-key) context */ +struct vmac_tfm_ctx { + struct crypto_cipher *cipher; + u64 nhkey[(VMAC_NHBYTES/8)+2*(VMAC_TAG_LEN/64-1)]; + u64 polykey[2*VMAC_TAG_LEN/64]; + u64 l3key[2*VMAC_TAG_LEN/64]; +}; + +/* per-request context */ +struct vmac_desc_ctx { + union { + u8 partial[VMAC_NHBYTES]; /* partial block */ + __le64 partial_words[VMAC_NHBYTES / 8]; + }; + unsigned int partial_size; /* size of the partial block */ + bool first_block_processed; + u64 polytmp[2*VMAC_TAG_LEN/64]; /* running total of L2-hash */ +}; + /* * Constants and masks */ @@ -318,13 +349,6 @@ static void poly_step_func(u64 *ahi, u64 *alo, } while (0) #endif -static void vhash_abort(struct vmac_ctx *ctx) -{ - ctx->polytmp[0] = ctx->polykey[0] ; - ctx->polytmp[1] = ctx->polykey[1] ; - ctx->first_block_processed = 0; -} - static u64 l3hash(u64 p1, u64 p2, u64 k1, u64 k2, u64 len) { u64 rh, rl, t, z = 0; @@ -364,280 +388,209 @@ static u64 l3hash(u64 p1, u64 p2, u64 k1, u64 k2, u64 len) return rl; } -static void vhash_update(const unsigned char *m, - unsigned int mbytes, /* Pos multiple of VMAC_NHBYTES */ - struct vmac_ctx *ctx) +/* L1 and L2-hash one or more VMAC_NHBYTES-byte blocks */ +static void vhash_blocks(const struct vmac_tfm_ctx *tctx, + struct vmac_desc_ctx *dctx, + const __le64 *mptr, unsigned int blocks) { - u64 rh, rl, *mptr; - const u64 *kptr = (u64 *)ctx->nhkey; - int i; - u64 ch, cl; - u64 pkh = ctx->polykey[0]; - u64 pkl = ctx->polykey[1]; - - if (!mbytes) - return; - - BUG_ON(mbytes % VMAC_NHBYTES); - - mptr = (u64 *)m; - i = mbytes / VMAC_NHBYTES; /* Must be non-zero */ - - ch = ctx->polytmp[0]; - cl = ctx->polytmp[1]; - - if (!ctx->first_block_processed) { - ctx->first_block_processed = 1; + const u64 *kptr = tctx->nhkey; + const u64 pkh = tctx->polykey[0]; + const u64 pkl = tctx->polykey[1]; + u64 ch = dctx->polytmp[0]; + u64 cl = dctx->polytmp[1]; + u64 rh, rl; + + if (!dctx->first_block_processed) { + dctx->first_block_processed = true; nh_vmac_nhbytes(mptr, kptr, VMAC_NHBYTES/8, rh, rl); rh &= m62; ADD128(ch, cl, rh, rl); mptr += (VMAC_NHBYTES/sizeof(u64)); - i--; + blocks--; } - while (i--) { + while (blocks--) { nh_vmac_nhbytes(mptr, kptr, VMAC_NHBYTES/8, rh, rl); rh &= m62; poly_step(ch, cl, pkh, pkl, rh, rl); mptr += (VMAC_NHBYTES/sizeof(u64)); } - ctx->polytmp[0] = ch; - ctx->polytmp[1] = cl; + dctx->polytmp[0] = ch; + dctx->polytmp[1] = cl; } -static u64 vhash(unsigned char m[], unsigned int mbytes, - u64 *tagl, struct vmac_ctx *ctx) +static int vmac_setkey(struct crypto_shash *tfm, + const u8 *key, unsigned int keylen) { - u64 rh, rl, *mptr; - const u64 *kptr = (u64 *)ctx->nhkey; - int i, remaining; - u64 ch, cl; - u64 pkh = ctx->polykey[0]; - u64 pkl = ctx->polykey[1]; - - mptr = (u64 *)m; - i = mbytes / VMAC_NHBYTES; - remaining = mbytes % VMAC_NHBYTES; - - if (ctx->first_block_processed) { - ch = ctx->polytmp[0]; - cl = ctx->polytmp[1]; - } else if (i) { - nh_vmac_nhbytes(mptr, kptr, VMAC_NHBYTES/8, ch, cl); - ch &= m62; - ADD128(ch, cl, pkh, pkl); - mptr += (VMAC_NHBYTES/sizeof(u64)); - i--; - } else if (remaining) { - nh_16(mptr, kptr, 2*((remaining+15)/16), ch, cl); - ch &= m62; - ADD128(ch, cl, pkh, pkl); - mptr += (VMAC_NHBYTES/sizeof(u64)); - goto do_l3; - } else {/* Empty String */ - ch = pkh; cl = pkl; - goto do_l3; - } - - while (i--) { - nh_vmac_nhbytes(mptr, kptr, VMAC_NHBYTES/8, rh, rl); - rh &= m62; - poly_step(ch, cl, pkh, pkl, rh, rl); - mptr += (VMAC_NHBYTES/sizeof(u64)); - } - if (remaining) { - nh_16(mptr, kptr, 2*((remaining+15)/16), rh, rl); - rh &= m62; - poly_step(ch, cl, pkh, pkl, rh, rl); - } - -do_l3: - vhash_abort(ctx); - remaining *= 8; - return l3hash(ch, cl, ctx->l3key[0], ctx->l3key[1], remaining); -} + struct vmac_tfm_ctx *tctx = crypto_shash_ctx(tfm); + __be64 out[2]; + u8 in[16] = { 0 }; + unsigned int i; + int err; -static u64 vmac(unsigned char m[], unsigned int mbytes, - const unsigned char n[16], u64 *tagl, - struct vmac_ctx_t *ctx) -{ - u64 *in_n, *out_p; - u64 p, h; - int i; - - in_n = ctx->__vmac_ctx.cached_nonce; - out_p = ctx->__vmac_ctx.cached_aes; - - i = n[15] & 1; - if ((*(u64 *)(n+8) != in_n[1]) || (*(u64 *)(n) != in_n[0])) { - in_n[0] = *(u64 *)(n); - in_n[1] = *(u64 *)(n+8); - ((unsigned char *)in_n)[15] &= 0xFE; - crypto_cipher_encrypt_one(ctx->child, - (unsigned char *)out_p, (unsigned char *)in_n); - - ((unsigned char *)in_n)[15] |= (unsigned char)(1-i); + if (keylen != VMAC_KEY_LEN) { + crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; } - p = be64_to_cpup(out_p + i); - h = vhash(m, mbytes, (u64 *)0, &ctx->__vmac_ctx); - return le64_to_cpu(p + h); -} -static int vmac_set_key(unsigned char user_key[], struct vmac_ctx_t *ctx) -{ - u64 in[2] = {0}, out[2]; - unsigned i; - int err = 0; - - err = crypto_cipher_setkey(ctx->child, user_key, VMAC_KEY_LEN); + err = crypto_cipher_setkey(tctx->cipher, key, keylen); if (err) return err; /* Fill nh key */ - ((unsigned char *)in)[0] = 0x80; - for (i = 0; i < sizeof(ctx->__vmac_ctx.nhkey)/8; i += 2) { - crypto_cipher_encrypt_one(ctx->child, - (unsigned char *)out, (unsigned char *)in); - ctx->__vmac_ctx.nhkey[i] = be64_to_cpup(out); - ctx->__vmac_ctx.nhkey[i+1] = be64_to_cpup(out+1); - ((unsigned char *)in)[15] += 1; + in[0] = 0x80; + for (i = 0; i < ARRAY_SIZE(tctx->nhkey); i += 2) { + crypto_cipher_encrypt_one(tctx->cipher, (u8 *)out, in); + tctx->nhkey[i] = be64_to_cpu(out[0]); + tctx->nhkey[i+1] = be64_to_cpu(out[1]); + in[15]++; } /* Fill poly key */ - ((unsigned char *)in)[0] = 0xC0; - in[1] = 0; - for (i = 0; i < sizeof(ctx->__vmac_ctx.polykey)/8; i += 2) { - crypto_cipher_encrypt_one(ctx->child, - (unsigned char *)out, (unsigned char *)in); - ctx->__vmac_ctx.polytmp[i] = - ctx->__vmac_ctx.polykey[i] = - be64_to_cpup(out) & mpoly; - ctx->__vmac_ctx.polytmp[i+1] = - ctx->__vmac_ctx.polykey[i+1] = - be64_to_cpup(out+1) & mpoly; - ((unsigned char *)in)[15] += 1; + in[0] = 0xC0; + in[15] = 0; + for (i = 0; i < ARRAY_SIZE(tctx->polykey); i += 2) { + crypto_cipher_encrypt_one(tctx->cipher, (u8 *)out, in); + tctx->polykey[i] = be64_to_cpu(out[0]) & mpoly; + tctx->polykey[i+1] = be64_to_cpu(out[1]) & mpoly; + in[15]++; } /* Fill ip key */ - ((unsigned char *)in)[0] = 0xE0; - in[1] = 0; - for (i = 0; i < sizeof(ctx->__vmac_ctx.l3key)/8; i += 2) { + in[0] = 0xE0; + in[15] = 0; + for (i = 0; i < ARRAY_SIZE(tctx->l3key); i += 2) { do { - crypto_cipher_encrypt_one(ctx->child, - (unsigned char *)out, (unsigned char *)in); - ctx->__vmac_ctx.l3key[i] = be64_to_cpup(out); - ctx->__vmac_ctx.l3key[i+1] = be64_to_cpup(out+1); - ((unsigned char *)in)[15] += 1; - } while (ctx->__vmac_ctx.l3key[i] >= p64 - || ctx->__vmac_ctx.l3key[i+1] >= p64); + crypto_cipher_encrypt_one(tctx->cipher, (u8 *)out, in); + tctx->l3key[i] = be64_to_cpu(out[0]); + tctx->l3key[i+1] = be64_to_cpu(out[1]); + in[15]++; + } while (tctx->l3key[i] >= p64 || tctx->l3key[i+1] >= p64); } - /* Invalidate nonce/aes cache and reset other elements */ - ctx->__vmac_ctx.cached_nonce[0] = (u64)-1; /* Ensure illegal nonce */ - ctx->__vmac_ctx.cached_nonce[1] = (u64)0; /* Ensure illegal nonce */ - ctx->__vmac_ctx.first_block_processed = 0; - - return err; + return 0; } -static int vmac_setkey(struct crypto_shash *parent, - const u8 *key, unsigned int keylen) +static int vmac_init(struct shash_desc *desc) { - struct vmac_ctx_t *ctx = crypto_shash_ctx(parent); + const struct vmac_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm); + struct vmac_desc_ctx *dctx = shash_desc_ctx(desc); - if (keylen != VMAC_KEY_LEN) { - crypto_shash_set_flags(parent, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -EINVAL; - } - - return vmac_set_key((u8 *)key, ctx); -} - -static int vmac_init(struct shash_desc *pdesc) -{ + dctx->partial_size = 0; + dctx->first_block_processed = false; + memcpy(dctx->polytmp, tctx->polykey, sizeof(dctx->polytmp)); return 0; } -static int vmac_update(struct shash_desc *pdesc, const u8 *p, - unsigned int len) +static int vmac_update(struct shash_desc *desc, const u8 *p, unsigned int len) { - struct crypto_shash *parent = pdesc->tfm; - struct vmac_ctx_t *ctx = crypto_shash_ctx(parent); - int expand; - int min; - - expand = VMAC_NHBYTES - ctx->partial_size > 0 ? - VMAC_NHBYTES - ctx->partial_size : 0; - - min = len < expand ? len : expand; - - memcpy(ctx->partial + ctx->partial_size, p, min); - ctx->partial_size += min; - - if (len < expand) - return 0; - - vhash_update(ctx->partial, VMAC_NHBYTES, &ctx->__vmac_ctx); - ctx->partial_size = 0; - - len -= expand; - p += expand; + const struct vmac_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm); + struct vmac_desc_ctx *dctx = shash_desc_ctx(desc); + unsigned int n; + + if (dctx->partial_size) { + n = min(len, VMAC_NHBYTES - dctx->partial_size); + memcpy(&dctx->partial[dctx->partial_size], p, n); + dctx->partial_size += n; + p += n; + len -= n; + if (dctx->partial_size == VMAC_NHBYTES) { + vhash_blocks(tctx, dctx, dctx->partial_words, 1); + dctx->partial_size = 0; + } + } - if (len % VMAC_NHBYTES) { - memcpy(ctx->partial, p + len - (len % VMAC_NHBYTES), - len % VMAC_NHBYTES); - ctx->partial_size = len % VMAC_NHBYTES; + if (len >= VMAC_NHBYTES) { + n = round_down(len, VMAC_NHBYTES); + /* TODO: 'p' may be misaligned here */ + vhash_blocks(tctx, dctx, (const __le64 *)p, n / VMAC_NHBYTES); + p += n; + len -= n; } - vhash_update(p, len - len % VMAC_NHBYTES, &ctx->__vmac_ctx); + if (len) { + memcpy(dctx->partial, p, len); + dctx->partial_size = len; + } return 0; } -static int vmac_final(struct shash_desc *pdesc, u8 *out) +static u64 vhash_final(const struct vmac_tfm_ctx *tctx, + struct vmac_desc_ctx *dctx) { - struct crypto_shash *parent = pdesc->tfm; - struct vmac_ctx_t *ctx = crypto_shash_ctx(parent); - vmac_t mac; - u8 nonce[16] = {}; - - /* vmac() ends up accessing outside the array bounds that - * we specify. In appears to access up to the next 2-word - * boundary. We'll just be uber cautious and zero the - * unwritten bytes in the buffer. - */ - if (ctx->partial_size) { - memset(ctx->partial + ctx->partial_size, 0, - VMAC_NHBYTES - ctx->partial_size); + unsigned int partial = dctx->partial_size; + u64 ch = dctx->polytmp[0]; + u64 cl = dctx->polytmp[1]; + + /* L1 and L2-hash the final block if needed */ + if (partial) { + /* Zero-pad to next 128-bit boundary */ + unsigned int n = round_up(partial, 16); + u64 rh, rl; + + memset(&dctx->partial[partial], 0, n - partial); + nh_16(dctx->partial_words, tctx->nhkey, n / 8, rh, rl); + rh &= m62; + if (dctx->first_block_processed) + poly_step(ch, cl, tctx->polykey[0], tctx->polykey[1], + rh, rl); + else + ADD128(ch, cl, rh, rl); } - mac = vmac(ctx->partial, ctx->partial_size, nonce, NULL, ctx); - memcpy(out, &mac, sizeof(vmac_t)); - memzero_explicit(&mac, sizeof(vmac_t)); - memset(&ctx->__vmac_ctx, 0, sizeof(struct vmac_ctx)); - ctx->partial_size = 0; + + /* L3-hash the 128-bit output of L2-hash */ + return l3hash(ch, cl, tctx->l3key[0], tctx->l3key[1], partial * 8); +} + +static int vmac_final(struct shash_desc *desc, u8 *out) +{ + const struct vmac_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm); + struct vmac_desc_ctx *dctx = shash_desc_ctx(desc); + static const u8 nonce[16] = {}; /* TODO: this is insecure */ + union { + u8 bytes[16]; + __be64 pads[2]; + } block; + int index; + u64 hash, pad; + + /* Finish calculating the VHASH of the message */ + hash = vhash_final(tctx, dctx); + + /* Generate pseudorandom pad by encrypting the nonce */ + memcpy(&block, nonce, 16); + index = block.bytes[15] & 1; + block.bytes[15] &= ~1; + crypto_cipher_encrypt_one(tctx->cipher, block.bytes, block.bytes); + pad = be64_to_cpu(block.pads[index]); + + /* The VMAC is the sum of VHASH and the pseudorandom pad */ + put_unaligned_le64(hash + pad, out); return 0; } static int vmac_init_tfm(struct crypto_tfm *tfm) { - struct crypto_cipher *cipher; - struct crypto_instance *inst = (void *)tfm->__crt_alg; + struct crypto_instance *inst = crypto_tfm_alg_instance(tfm); struct crypto_spawn *spawn = crypto_instance_ctx(inst); - struct vmac_ctx_t *ctx = crypto_tfm_ctx(tfm); + struct vmac_tfm_ctx *tctx = crypto_tfm_ctx(tfm); + struct crypto_cipher *cipher; cipher = crypto_spawn_cipher(spawn); if (IS_ERR(cipher)) return PTR_ERR(cipher); - ctx->child = cipher; + tctx->cipher = cipher; return 0; } static void vmac_exit_tfm(struct crypto_tfm *tfm) { - struct vmac_ctx_t *ctx = crypto_tfm_ctx(tfm); - crypto_free_cipher(ctx->child); + struct vmac_tfm_ctx *tctx = crypto_tfm_ctx(tfm); + + crypto_free_cipher(tctx->cipher); } static int vmac_create(struct crypto_template *tmpl, struct rtattr **tb) @@ -655,6 +608,10 @@ static int vmac_create(struct crypto_template *tmpl, struct rtattr **tb) if (IS_ERR(alg)) return PTR_ERR(alg); + err = -EINVAL; + if (alg->cra_blocksize != 16) + goto out_put_alg; + inst = shash_alloc_instance("vmac", alg); err = PTR_ERR(inst); if (IS_ERR(inst)) @@ -670,11 +627,12 @@ static int vmac_create(struct crypto_template *tmpl, struct rtattr **tb) inst->alg.base.cra_blocksize = alg->cra_blocksize; inst->alg.base.cra_alignmask = alg->cra_alignmask; - inst->alg.digestsize = sizeof(vmac_t); - inst->alg.base.cra_ctxsize = sizeof(struct vmac_ctx_t); + inst->alg.base.cra_ctxsize = sizeof(struct vmac_tfm_ctx); inst->alg.base.cra_init = vmac_init_tfm; inst->alg.base.cra_exit = vmac_exit_tfm; + inst->alg.descsize = sizeof(struct vmac_desc_ctx); + inst->alg.digestsize = VMAC_TAG_LEN / 8; inst->alg.init = vmac_init; inst->alg.update = vmac_update; inst->alg.final = vmac_final; diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 572b6c7303edce1aa6f097c310bad0aa3b218661..f14695e744d0313dfba260371a07944bf2f18da6 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -114,19 +114,7 @@ static DEFINE_MUTEX(ghes_list_mutex); * from BIOS to Linux can be determined only in NMI, IRQ or timer * handler, but general ioremap can not be used in atomic context, so * the fixmap is used instead. - */ - -/* - * Two virtual pages are used, one for IRQ/PROCESS context, the other for - * NMI context (optionally). - */ -#define GHES_IOREMAP_PAGES 2 -#define GHES_IOREMAP_IRQ_PAGE(base) (base) -#define GHES_IOREMAP_NMI_PAGE(base) ((base) + PAGE_SIZE) - -/* virtual memory area for atomic ioremap */ -static struct vm_struct *ghes_ioremap_area; -/* + * * These 2 spinlocks are used to prevent the fixmap entries from being used * simultaneously. */ @@ -141,23 +129,6 @@ static atomic_t ghes_estatus_cache_alloced; static int ghes_panic_timeout __read_mostly = 30; -static int ghes_ioremap_init(void) -{ - ghes_ioremap_area = __get_vm_area(PAGE_SIZE * GHES_IOREMAP_PAGES, - VM_IOREMAP, VMALLOC_START, VMALLOC_END); - if (!ghes_ioremap_area) { - pr_err(GHES_PFX "Failed to allocate virtual memory area for atomic ioremap.\n"); - return -ENOMEM; - } - - return 0; -} - -static void ghes_ioremap_exit(void) -{ - free_vm_area(ghes_ioremap_area); -} - static void __iomem *ghes_ioremap_pfn_nmi(u64 pfn) { phys_addr_t paddr; @@ -1247,13 +1218,9 @@ static int __init ghes_init(void) ghes_nmi_init_cxt(); - rc = ghes_ioremap_init(); - if (rc) - goto err; - rc = ghes_estatus_pool_init(); if (rc) - goto err_ioremap_exit; + goto err; rc = ghes_estatus_pool_expand(GHES_ESTATUS_CACHE_AVG_SIZE * GHES_ESTATUS_CACHE_ALLOCED_MAX); @@ -1277,8 +1244,6 @@ static int __init ghes_init(void) return 0; err_pool_exit: ghes_estatus_pool_exit(); -err_ioremap_exit: - ghes_ioremap_exit(); err: return rc; } diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 30a5729565575f83cb02700ac2050f35abab5e5d..70a0f8b2f6c13a5416866141370d36a91dfbffda 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -2031,6 +2031,17 @@ static inline void acpi_ec_query_exit(void) } } +static const struct dmi_system_id acpi_ec_no_wakeup[] = { + { + .ident = "Thinkpad X1 Carbon 6th", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_FAMILY, "Thinkpad X1 Carbon 6th"), + }, + }, + { }, +}; + int __init acpi_ec_init(void) { int result; @@ -2041,6 +2052,15 @@ int __init acpi_ec_init(void) if (result) return result; + /* + * Disable EC wakeup on following systems to prevent periodic + * wakeup from EC GPE. + */ + if (dmi_check_system(acpi_ec_no_wakeup)) { + ec_no_wakeup = true; + pr_debug("Disabling EC wakeup on suspend-to-idle\n"); + } + /* Drivers must be started after acpi_ec_query_init() */ dsdt_fail = acpi_bus_register_driver(&acpi_ec_driver); /* diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index d56822f58ab124143baef6fa2a5322db5dcef0f0..8260b90eb64b2e7e020f5e316eef5c0585d7ccb8 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -224,6 +224,8 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, const guid_t *guid; int rc, i; + if (cmd_rc) + *cmd_rc = -EINVAL; func = cmd; if (cmd == ND_CMD_CALL) { call_pkg = buf; @@ -314,6 +316,8 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, * If we return an error (like elsewhere) then caller wouldn't * be able to rely upon data returned to make calculation. */ + if (cmd_rc) + *cmd_rc = 0; return 0; } diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index c0984d33c4c856dae04fc4eb7b111e24d287a120..2eddbb1fae6a0be9418002ff147968a24195ffb4 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1599,7 +1599,8 @@ static int acpi_add_single_object(struct acpi_device **child, * Note this must be done before the get power-/wakeup_dev-flags calls. */ if (type == ACPI_BUS_TYPE_DEVICE) - acpi_bus_get_status(device); + if (acpi_bus_get_status(device) < 0) + acpi_set_device_status(device, 0); acpi_bus_get_power_flags(device); acpi_bus_get_wakeup_device_flags(device); @@ -1677,7 +1678,7 @@ static int acpi_bus_type_and_status(acpi_handle handle, int *type, * acpi_add_single_object updates this once we've an acpi_device * so that acpi_bus_get_status' quirk handling can be used. */ - *sta = 0; + *sta = ACPI_STA_DEFAULT; break; case ACPI_TYPE_PROCESSOR: *type = ACPI_BUS_TYPE_PROCESSOR; diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 2ef0ad6a33d6c692da5465a817ebfde87620c8c6..7a0af16f86f204f60a9fc4202a34f2853a91518f 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -338,6 +338,14 @@ static const struct dmi_system_id acpisleep_dmi_table[] __initconst = { DMI_MATCH(DMI_PRODUCT_NAME, "K54HR"), }, }, + { + .callback = init_nvs_save_s3, + .ident = "Asus 1025C", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "1025C"), + }, + }, /* * https://bugzilla.kernel.org/show_bug.cgi?id=189431 * Lenovo G50-45 is a platform later than 2012, but needs nvs memory diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 4f382d51def11f4816694be6e7e02aa1598f720f..54debce30ee079a4a6925d3aa625769b911697c8 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -327,6 +327,34 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate, return vma ? -ENOMEM : -ESRCH; } +static inline void binder_alloc_set_vma(struct binder_alloc *alloc, + struct vm_area_struct *vma) +{ + if (vma) + alloc->vma_vm_mm = vma->vm_mm; + /* + * If we see alloc->vma is not NULL, buffer data structures set up + * completely. Look at smp_rmb side binder_alloc_get_vma. + * We also want to guarantee new alloc->vma_vm_mm is always visible + * if alloc->vma is set. + */ + smp_wmb(); + alloc->vma = vma; +} + +static inline struct vm_area_struct *binder_alloc_get_vma( + struct binder_alloc *alloc) +{ + struct vm_area_struct *vma = NULL; + + if (alloc->vma) { + /* Look at description in binder_alloc_set_vma */ + smp_rmb(); + vma = alloc->vma; + } + return vma; +} + static struct binder_buffer *binder_alloc_new_buf_locked( struct binder_alloc *alloc, size_t data_size, @@ -343,7 +371,7 @@ static struct binder_buffer *binder_alloc_new_buf_locked( size_t size, data_offsets_size; int ret; - if (alloc->vma == NULL) { + if (!binder_alloc_get_vma(alloc)) { pr_err("%d: binder_alloc_buf, no vma\n", alloc->pid); return ERR_PTR(-ESRCH); @@ -714,9 +742,7 @@ int binder_alloc_mmap_handler(struct binder_alloc *alloc, buffer->free = 1; binder_insert_free_buffer(alloc, buffer); alloc->free_async_space = alloc->buffer_size / 2; - barrier(); - alloc->vma = vma; - alloc->vma_vm_mm = vma->vm_mm; + binder_alloc_set_vma(alloc, vma); mmgrab(alloc->vma_vm_mm); return 0; @@ -743,10 +769,10 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc) int buffers, page_count; struct binder_buffer *buffer; - BUG_ON(alloc->vma); - buffers = 0; mutex_lock(&alloc->mutex); + BUG_ON(alloc->vma); + while ((n = rb_first(&alloc->allocated_buffers))) { buffer = rb_entry(n, struct binder_buffer, rb_node); @@ -889,7 +915,7 @@ int binder_alloc_get_allocated_count(struct binder_alloc *alloc) */ void binder_alloc_vma_close(struct binder_alloc *alloc) { - WRITE_ONCE(alloc->vma, NULL); + binder_alloc_set_vma(alloc, NULL); } /** @@ -924,7 +950,7 @@ enum lru_status binder_alloc_free_page(struct list_head *item, index = page - alloc->pages; page_addr = (uintptr_t)alloc->buffer + index * PAGE_SIZE; - vma = alloc->vma; + vma = binder_alloc_get_vma(alloc); if (vma) { if (!mmget_not_zero(alloc->vma_vm_mm)) goto err_mmget; diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 5ae268b8514e228b9b7830ad8346e029e7984f13..cda9a0b5bdaaa2c9783f460c8c8a1594e55cb1ae 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -1135,10 +1136,12 @@ static ssize_t ahci_led_store(struct ata_port *ap, const char *buf, /* get the slot number from the message */ pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8; - if (pmp < EM_MAX_SLOTS) + if (pmp < EM_MAX_SLOTS) { + pmp = array_index_nospec(pmp, EM_MAX_SLOTS); emp = &pp->em_priv[pmp]; - else + } else { return -EINVAL; + } /* mask off the activity bits if we are in sw_activity * mode, user should turn off sw_activity before setting @@ -2093,7 +2096,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) struct ahci_host_priv *hpriv = ap->host->private_data; void __iomem *port_mmio = ahci_port_base(ap); struct ata_device *dev = ap->link.device; - u32 devslp, dm, dito, mdat, deto; + u32 devslp, dm, dito, mdat, deto, dito_conf; int rc; unsigned int err_mask; @@ -2117,8 +2120,15 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) return; } - /* device sleep was already enabled */ - if (devslp & PORT_DEVSLP_ADSE) + dm = (devslp & PORT_DEVSLP_DM_MASK) >> PORT_DEVSLP_DM_OFFSET; + dito = devslp_idle_timeout / (dm + 1); + if (dito > 0x3ff) + dito = 0x3ff; + + dito_conf = (devslp >> PORT_DEVSLP_DITO_OFFSET) & 0x3FF; + + /* device sleep was already enabled and same dito */ + if ((devslp & PORT_DEVSLP_ADSE) && (dito_conf == dito)) return; /* set DITO, MDAT, DETO and enable DevSlp, need to stop engine first */ @@ -2126,11 +2136,6 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) if (rc) return; - dm = (devslp & PORT_DEVSLP_DM_MASK) >> PORT_DEVSLP_DM_OFFSET; - dito = devslp_idle_timeout / (dm + 1); - if (dito > 0x3ff) - dito = 0x3ff; - /* Use the nominal value 10 ms if the read MDAT is zero, * the nominal value of DETO is 20 ms. */ @@ -2148,6 +2153,8 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) deto = 20; } + /* Make dito, mdat, deto bits to 0s */ + devslp &= ~GENMASK_ULL(24, 2); devslp |= ((dito << PORT_DEVSLP_DITO_OFFSET) | (mdat << PORT_DEVSLP_MDAT_OFFSET) | (deto << PORT_DEVSLP_DETO_OFFSET) | diff --git a/drivers/ata/pata_ftide010.c b/drivers/ata/pata_ftide010.c index 5d4b72e21161a888c44997b448f602cef99a6709..569a4a662dcd4deb9d9edb0dbca4001f798bcab5 100644 --- a/drivers/ata/pata_ftide010.c +++ b/drivers/ata/pata_ftide010.c @@ -256,14 +256,12 @@ static struct ata_port_operations pata_ftide010_port_ops = { .qc_issue = ftide010_qc_issue, }; -static struct ata_port_info ftide010_port_info[] = { - { - .flags = ATA_FLAG_SLAVE_POSS, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA6, - .pio_mask = ATA_PIO4, - .port_ops = &pata_ftide010_port_ops, - }, +static struct ata_port_info ftide010_port_info = { + .flags = ATA_FLAG_SLAVE_POSS, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA6, + .pio_mask = ATA_PIO4, + .port_ops = &pata_ftide010_port_ops, }; #if IS_ENABLED(CONFIG_SATA_GEMINI) @@ -349,6 +347,7 @@ static int pata_ftide010_gemini_cable_detect(struct ata_port *ap) } static int pata_ftide010_gemini_init(struct ftide010 *ftide, + struct ata_port_info *pi, bool is_ata1) { struct device *dev = ftide->dev; @@ -373,7 +372,13 @@ static int pata_ftide010_gemini_init(struct ftide010 *ftide, /* Flag port as SATA-capable */ if (gemini_sata_bridge_enabled(sg, is_ata1)) - ftide010_port_info[0].flags |= ATA_FLAG_SATA; + pi->flags |= ATA_FLAG_SATA; + + /* This device has broken DMA, only PIO works */ + if (of_machine_is_compatible("itian,sq201")) { + pi->mwdma_mask = 0; + pi->udma_mask = 0; + } /* * We assume that a simple 40-wire cable is used in the PATA mode. @@ -435,6 +440,7 @@ static int pata_ftide010_gemini_init(struct ftide010 *ftide, } #else static int pata_ftide010_gemini_init(struct ftide010 *ftide, + struct ata_port_info *pi, bool is_ata1) { return -ENOTSUPP; @@ -446,7 +452,7 @@ static int pata_ftide010_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - const struct ata_port_info pi = ftide010_port_info[0]; + struct ata_port_info pi = ftide010_port_info; const struct ata_port_info *ppi[] = { &pi, NULL }; struct ftide010 *ftide; struct resource *res; @@ -490,6 +496,7 @@ static int pata_ftide010_probe(struct platform_device *pdev) * are ATA0. This will also set up the cable types. */ ret = pata_ftide010_gemini_init(ftide, + &pi, (res->start == 0x63400000)); if (ret) goto err_dis_clk; diff --git a/drivers/base/core.c b/drivers/base/core.c index 9db30ee99917bfb245965149ef6656a14266e65c..b472de3ab925d3ac52162812e892c65adc40eb49 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -2788,6 +2788,9 @@ void device_shutdown(void) { struct device *dev, *parent; + wait_for_device_probe(); + device_block_probing(); + spin_lock(&devices_kset->list_lock); /* * Walk the devices list backward, shutting down each in turn. diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index ff58c8efa1efaf86e704688402a497eb10ae1c3a..1505da863ea42b61d54c319770f63c359e51319c 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -618,16 +618,24 @@ ssize_t __weak cpu_show_spec_store_bypass(struct device *dev, return sprintf(buf, "Not affected\n"); } +ssize_t __weak cpu_show_l1tf(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "Not affected\n"); +} + static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL); static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL); static DEVICE_ATTR(spectre_v2, 0444, cpu_show_spectre_v2, NULL); static DEVICE_ATTR(spec_store_bypass, 0444, cpu_show_spec_store_bypass, NULL); +static DEVICE_ATTR(l1tf, 0444, cpu_show_l1tf, NULL); static struct attribute *cpu_root_vulnerabilities_attrs[] = { &dev_attr_meltdown.attr, &dev_attr_spectre_v1.attr, &dev_attr_spectre_v2.attr, &dev_attr_spec_store_bypass.attr, + &dev_attr_l1tf.attr, NULL }; diff --git a/drivers/base/dma-coherent.c b/drivers/base/dma-coherent.c index 23b2b3c46d0eec349500a62c796866fcc0c52f21..1e6396bb807b1255ab61e0a168e1b7eac40f892c 100644 --- a/drivers/base/dma-coherent.c +++ b/drivers/base/dma-coherent.c @@ -168,9 +168,6 @@ static void *__dma_alloc_from_coherent(struct dma_coherent_mem *mem, int pageno; void *ret; - if (order > CONFIG_CMA_ALIGNMENT) - order = CONFIG_CMA_ALIGNMENT; - spin_lock_irqsave(&mem->spinlock, flags); if (unlikely(size > (mem->size << PAGE_SHIFT))) diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c index 8e2e4757adcb02c9cd07a0b868a45e0bb3baa3eb..5a42ae4078c27febf8194901d8fa0e30b43bd1aa 100644 --- a/drivers/base/power/clock_ops.c +++ b/drivers/base/power/clock_ops.c @@ -185,7 +185,7 @@ EXPORT_SYMBOL_GPL(of_pm_clk_add_clk); int of_pm_clk_add_clks(struct device *dev) { struct clk **clks; - unsigned int i, count; + int i, count; int ret; if (!dev || !dev->of_node) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index e24f6500786e32f0c2a3d585c88975db2cdd85bf..594581a0c973b78f20e09f8795ce7ae36fafc40b 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -1464,8 +1464,10 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) dpm_wait_for_subordinate(dev, async); - if (async_error) + if (async_error) { + dev->power.direct_complete = false; goto Complete; + } /* * If a device configured to wake up the system from sleep states @@ -1480,6 +1482,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) pm_get_active_wakeup_sources(suspend_abort, MAX_SUSPEND_ABORT_LEN); log_suspend_abort_reason(suspend_abort); + dev->power.direct_complete = false; async_error = -EBUSY; goto Complete; } diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index de8566e5533499b6170c669a08c2aa8688e67057..c72071c300bbb74cdd4c7a7081f5b6f6a2c7b277 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -1244,8 +1244,8 @@ drbd_request_prepare(struct drbd_device *device, struct bio *bio, unsigned long _drbd_start_io_acct(device, req); /* process discards always from our submitter thread */ - if ((bio_op(bio) & REQ_OP_WRITE_ZEROES) || - (bio_op(bio) & REQ_OP_DISCARD)) + if (bio_op(bio) == REQ_OP_WRITE_ZEROES || + bio_op(bio) == REQ_OP_DISCARD) goto queue_for_submitter_thread; if (rw == WRITE && req->private_bio && req->i.size diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 60c086a536094d4c19ad31a023d49274d54c3dd5..3d0287e212fe5fb1a2042909fc4a8891a3e21d66 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -3462,6 +3462,9 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int (struct floppy_struct **)&outparam); if (ret) return ret; + memcpy(&inparam.g, outparam, + offsetof(struct floppy_struct, name)); + outparam = &inparam.g; break; case FDMSGON: UDP->flags |= FTD_MSG; diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 6fb64e73bc9678e079a77823b5e4a3e31dba8dca..fe1414df0f3319cb201eb9fb63b14c4773c1c3fa 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -76,6 +76,7 @@ struct link_dead_args { #define NBD_HAS_CONFIG_REF 4 #define NBD_BOUND 5 #define NBD_DESTROY_ON_DISCONNECT 6 +#define NBD_DISCONNECT_ON_CLOSE 7 struct nbd_config { u32 flags; @@ -111,12 +112,16 @@ struct nbd_device { struct task_struct *task_setup; }; +#define NBD_CMD_REQUEUED 1 + struct nbd_cmd { struct nbd_device *nbd; + struct mutex lock; int index; int cookie; - struct completion send_complete; blk_status_t status; + unsigned long flags; + u32 cmd_cookie; }; #if IS_ENABLED(CONFIG_DEBUG_FS) @@ -138,12 +143,42 @@ static void nbd_config_put(struct nbd_device *nbd); static void nbd_connect_reply(struct genl_info *info, int index); static int nbd_genl_status(struct sk_buff *skb, struct genl_info *info); static void nbd_dead_link_work(struct work_struct *work); +static void nbd_disconnect_and_put(struct nbd_device *nbd); static inline struct device *nbd_to_dev(struct nbd_device *nbd) { return disk_to_dev(nbd->disk); } +static void nbd_requeue_cmd(struct nbd_cmd *cmd) +{ + struct request *req = blk_mq_rq_from_pdu(cmd); + + if (!test_and_set_bit(NBD_CMD_REQUEUED, &cmd->flags)) + blk_mq_requeue_request(req, true); +} + +#define NBD_COOKIE_BITS 32 + +static u64 nbd_cmd_handle(struct nbd_cmd *cmd) +{ + struct request *req = blk_mq_rq_from_pdu(cmd); + u32 tag = blk_mq_unique_tag(req); + u64 cookie = cmd->cmd_cookie; + + return (cookie << NBD_COOKIE_BITS) | tag; +} + +static u32 nbd_handle_to_tag(u64 handle) +{ + return (u32)handle; +} + +static u32 nbd_handle_to_cookie(u64 handle) +{ + return (u32)(handle >> NBD_COOKIE_BITS); +} + static const char *nbdcmd_to_ascii(int cmd) { switch (cmd) { @@ -304,6 +339,9 @@ static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req, } config = nbd->config; + if (!mutex_trylock(&cmd->lock)) + return BLK_EH_RESET_TIMER; + if (config->num_connections > 1) { dev_err_ratelimited(nbd_to_dev(nbd), "Connection timed out, retrying\n"); @@ -326,7 +364,8 @@ static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req, nbd_mark_nsock_dead(nbd, nsock, 1); mutex_unlock(&nsock->tx_lock); } - blk_mq_requeue_request(req, true); + mutex_unlock(&cmd->lock); + nbd_requeue_cmd(cmd); nbd_config_put(nbd); return BLK_EH_NOT_HANDLED; } @@ -336,6 +375,7 @@ static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req, } set_bit(NBD_TIMEDOUT, &config->runtime_flags); cmd->status = BLK_STS_IOERR; + mutex_unlock(&cmd->lock); sock_shutdown(nbd); nbd_config_put(nbd); @@ -412,9 +452,9 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index) struct iov_iter from; unsigned long size = blk_rq_bytes(req); struct bio *bio; + u64 handle; u32 type; u32 nbd_cmd_flags = 0; - u32 tag = blk_mq_unique_tag(req); int sent = nsock->sent, skip = 0; iov_iter_kvec(&from, WRITE | ITER_KVEC, &iov, 1, sizeof(request)); @@ -456,6 +496,8 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index) goto send_pages; } iov_iter_advance(&from, sent); + } else { + cmd->cmd_cookie++; } cmd->index = index; cmd->cookie = nsock->cookie; @@ -464,7 +506,8 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index) request.from = cpu_to_be64((u64)blk_rq_pos(req) << 9); request.len = htonl(size); } - memcpy(request.handle, &tag, sizeof(tag)); + handle = nbd_cmd_handle(cmd); + memcpy(request.handle, &handle, sizeof(handle)); dev_dbg(nbd_to_dev(nbd), "request %p: sending control (%s@%llu,%uB)\n", cmd, nbdcmd_to_ascii(type), @@ -482,6 +525,7 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index) nsock->pending = req; nsock->sent = sent; } + set_bit(NBD_CMD_REQUEUED, &cmd->flags); return BLK_STS_RESOURCE; } dev_err_ratelimited(disk_to_dev(nbd->disk), @@ -523,6 +567,7 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index) */ nsock->pending = req; nsock->sent = sent; + set_bit(NBD_CMD_REQUEUED, &cmd->flags); return BLK_STS_RESOURCE; } dev_err(disk_to_dev(nbd->disk), @@ -555,10 +600,12 @@ static struct nbd_cmd *nbd_read_stat(struct nbd_device *nbd, int index) struct nbd_reply reply; struct nbd_cmd *cmd; struct request *req = NULL; + u64 handle; u16 hwq; u32 tag; struct kvec iov = {.iov_base = &reply, .iov_len = sizeof(reply)}; struct iov_iter to; + int ret = 0; reply.magic = 0; iov_iter_kvec(&to, READ | ITER_KVEC, &iov, 1, sizeof(reply)); @@ -576,8 +623,8 @@ static struct nbd_cmd *nbd_read_stat(struct nbd_device *nbd, int index) return ERR_PTR(-EPROTO); } - memcpy(&tag, reply.handle, sizeof(u32)); - + memcpy(&handle, reply.handle, sizeof(handle)); + tag = nbd_handle_to_tag(handle); hwq = blk_mq_unique_tag_to_hwq(tag); if (hwq < nbd->tag_set.nr_hw_queues) req = blk_mq_tag_to_rq(nbd->tag_set.tags[hwq], @@ -588,11 +635,25 @@ static struct nbd_cmd *nbd_read_stat(struct nbd_device *nbd, int index) return ERR_PTR(-ENOENT); } cmd = blk_mq_rq_to_pdu(req); + + mutex_lock(&cmd->lock); + if (cmd->cmd_cookie != nbd_handle_to_cookie(handle)) { + dev_err(disk_to_dev(nbd->disk), "Double reply on req %p, cmd_cookie %u, handle cookie %u\n", + req, cmd->cmd_cookie, nbd_handle_to_cookie(handle)); + ret = -ENOENT; + goto out; + } + if (test_bit(NBD_CMD_REQUEUED, &cmd->flags)) { + dev_err(disk_to_dev(nbd->disk), "Raced with timeout on req %p\n", + req); + ret = -ENOENT; + goto out; + } if (ntohl(reply.error)) { dev_err(disk_to_dev(nbd->disk), "Other side returned error (%d)\n", ntohl(reply.error)); cmd->status = BLK_STS_IOERR; - return cmd; + goto out; } dev_dbg(nbd_to_dev(nbd), "request %p: got reply\n", cmd); @@ -617,18 +678,18 @@ static struct nbd_cmd *nbd_read_stat(struct nbd_device *nbd, int index) if (nbd_disconnected(config) || config->num_connections <= 1) { cmd->status = BLK_STS_IOERR; - return cmd; + goto out; } - return ERR_PTR(-EIO); + ret = -EIO; + goto out; } dev_dbg(nbd_to_dev(nbd), "request %p: got %d bytes data\n", cmd, bvec.bv_len); } - } else { - /* See the comment in nbd_queue_rq. */ - wait_for_completion(&cmd->send_complete); } - return cmd; +out: + mutex_unlock(&cmd->lock); + return ret ? ERR_PTR(ret) : cmd; } static void recv_work(struct work_struct *work) @@ -791,7 +852,7 @@ static int nbd_handle_cmd(struct nbd_cmd *cmd, int index) */ blk_mq_start_request(req); if (unlikely(nsock->pending && nsock->pending != req)) { - blk_mq_requeue_request(req, true); + nbd_requeue_cmd(cmd); ret = 0; goto out; } @@ -804,7 +865,7 @@ static int nbd_handle_cmd(struct nbd_cmd *cmd, int index) dev_err_ratelimited(disk_to_dev(nbd->disk), "Request send failed, requeueing\n"); nbd_mark_nsock_dead(nbd, nsock, 1); - blk_mq_requeue_request(req, true); + nbd_requeue_cmd(cmd); ret = 0; } out: @@ -828,7 +889,8 @@ static blk_status_t nbd_queue_rq(struct blk_mq_hw_ctx *hctx, * that the server is misbehaving (or there was an error) before we're * done sending everything over the wire. */ - init_completion(&cmd->send_complete); + mutex_lock(&cmd->lock); + clear_bit(NBD_CMD_REQUEUED, &cmd->flags); /* We can be called directly from the user space process, which means we * could possibly have signals pending so our sendmsg will fail. In @@ -840,7 +902,7 @@ static blk_status_t nbd_queue_rq(struct blk_mq_hw_ctx *hctx, ret = BLK_STS_IOERR; else if (!ret) ret = BLK_STS_OK; - complete(&cmd->send_complete); + mutex_unlock(&cmd->lock); return ret; } @@ -1166,6 +1228,9 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd, case NBD_SET_SOCK: return nbd_add_socket(nbd, arg, false); case NBD_SET_BLKSIZE: + if (!arg || !is_power_of_2(arg) || arg < 512 || + arg > PAGE_SIZE) + return -EINVAL; nbd_size_set(nbd, arg, div_s64(config->bytesize, arg)); return 0; @@ -1291,6 +1356,12 @@ static int nbd_open(struct block_device *bdev, fmode_t mode) static void nbd_release(struct gendisk *disk, fmode_t mode) { struct nbd_device *nbd = disk->private_data; + struct block_device *bdev = bdget_disk(disk, 0); + + if (test_bit(NBD_DISCONNECT_ON_CLOSE, &nbd->config->runtime_flags) && + bdev->bd_openers == 0) + nbd_disconnect_and_put(nbd); + nbd_config_put(nbd); nbd_put(nbd); } @@ -1438,6 +1509,8 @@ static int nbd_init_request(struct blk_mq_tag_set *set, struct request *rq, { struct nbd_cmd *cmd = blk_mq_rq_to_pdu(rq); cmd->nbd = set->driver_data; + cmd->flags = 0; + mutex_init(&cmd->lock); return 0; } @@ -1690,6 +1763,10 @@ static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info) &config->runtime_flags); put_dev = true; } + if (flags & NBD_CFLAG_DISCONNECT_ON_CLOSE) { + set_bit(NBD_DISCONNECT_ON_CLOSE, + &config->runtime_flags); + } } if (info->attrs[NBD_ATTR_SOCKETS]) { @@ -1734,6 +1811,16 @@ static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info) return ret; } +static void nbd_disconnect_and_put(struct nbd_device *nbd) +{ + mutex_lock(&nbd->config_lock); + nbd_disconnect(nbd); + mutex_unlock(&nbd->config_lock); + if (test_and_clear_bit(NBD_HAS_CONFIG_REF, + &nbd->config->runtime_flags)) + nbd_config_put(nbd); +} + static int nbd_genl_disconnect(struct sk_buff *skb, struct genl_info *info) { struct nbd_device *nbd; @@ -1766,12 +1853,7 @@ static int nbd_genl_disconnect(struct sk_buff *skb, struct genl_info *info) nbd_put(nbd); return 0; } - mutex_lock(&nbd->config_lock); - nbd_disconnect(nbd); - mutex_unlock(&nbd->config_lock); - if (test_and_clear_bit(NBD_HAS_CONFIG_REF, - &nbd->config->runtime_flags)) - nbd_config_put(nbd); + nbd_disconnect_and_put(nbd); nbd_config_put(nbd); nbd_put(nbd); return 0; @@ -1782,7 +1864,7 @@ static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info) struct nbd_device *nbd = NULL; struct nbd_config *config; int index; - int ret = -EINVAL; + int ret = 0; bool put_dev = false; if (!netlink_capable(skb, CAP_SYS_ADMIN)) @@ -1822,6 +1904,7 @@ static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info) !nbd->task_recv) { dev_err(nbd_to_dev(nbd), "not configured, cannot reconfigure\n"); + ret = -EINVAL; goto out; } @@ -1846,6 +1929,14 @@ static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info) &config->runtime_flags)) refcount_inc(&nbd->refs); } + + if (flags & NBD_CFLAG_DISCONNECT_ON_CLOSE) { + set_bit(NBD_DISCONNECT_ON_CLOSE, + &config->runtime_flags); + } else { + clear_bit(NBD_DISCONNECT_ON_CLOSE, + &config->runtime_flags); + } } if (info->attrs[NBD_ATTR_SOCKETS]) { diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 531a0915066b313462d6208359ecea4102397215..11ec92e47455a3fafc4a853da977adb31ae2bde6 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -67,7 +67,7 @@ #include #include #include - +#include #include #define DRIVER_NAME "pktcdvd" @@ -2231,6 +2231,8 @@ static struct pktcdvd_device *pkt_find_dev_from_minor(unsigned int dev_minor) { if (dev_minor >= MAX_WRITERS) return NULL; + + dev_minor = array_index_nospec(dev_minor, MAX_WRITERS); return pkt_devs[dev_minor]; } diff --git a/drivers/block/zram/Kconfig b/drivers/block/zram/Kconfig index ac3a31d433b2e9f698d051bfcd06f76d0efad971..6620c7972e90c243cc6c1cbd80069d0f3773d766 100644 --- a/drivers/block/zram/Kconfig +++ b/drivers/block/zram/Kconfig @@ -15,6 +15,20 @@ config ZRAM See zram.txt for more information. +config ZRAM_DEDUP + bool "Deduplication support for ZRAM data" + depends on ZRAM + default n + help + Deduplicate ZRAM data to reduce amount of memory consumption. + Advantage largely depends on the workload. In some cases, this + option reduces memory usage to the half. However, if there is no + duplicated data, the amount of memory consumption would be + increased due to additional metadata usage. And, there is + computation time trade-off. Please check the benefit before + enabling this option. Experiment shows the positive effect when + the zram is used as blockdev and is used to store build output. + config ZRAM_WRITEBACK bool "Write back incompressible page to backing device" depends on ZRAM diff --git a/drivers/block/zram/Makefile b/drivers/block/zram/Makefile index 9e2b79e9a990b59ecc7868dd78ae1cc5cd13a595..d7204ef6ee53e1c34b1bc73f46848633b3aacab6 100644 --- a/drivers/block/zram/Makefile +++ b/drivers/block/zram/Makefile @@ -1,3 +1,4 @@ -zram-y := zcomp.o zram_drv.o +zram-y := zcomp.o zram_drv.o +zram-$(CONFIG_ZRAM_DEDUP) += zram_dedup.o obj-$(CONFIG_ZRAM) += zram.o diff --git a/drivers/block/zram/zram_dedup.c b/drivers/block/zram/zram_dedup.c new file mode 100644 index 0000000000000000000000000000000000000000..14c4988f8ff73c122bd0fb727e260a5077c1035f --- /dev/null +++ b/drivers/block/zram/zram_dedup.c @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2017 Joonsoo Kim. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include + +#include "zram_drv.h" + +/* One slot will contain 128 pages theoretically */ +#define ZRAM_HASH_SHIFT 7 +#define ZRAM_HASH_SIZE_MIN (1 << 10) +#define ZRAM_HASH_SIZE_MAX (1 << 31) + +u64 zram_dedup_dup_size(struct zram *zram) +{ + return (u64)atomic64_read(&zram->stats.dup_data_size); +} + +u64 zram_dedup_meta_size(struct zram *zram) +{ + return (u64)atomic64_read(&zram->stats.meta_data_size); +} + +static u32 zram_dedup_checksum(unsigned char *mem) +{ + return jhash(mem, PAGE_SIZE, 0); +} + +void zram_dedup_insert(struct zram *zram, struct zram_entry *new, + u32 checksum) +{ + struct zram_hash *hash; + struct rb_root *rb_root; + struct rb_node **rb_node, *parent = NULL; + struct zram_entry *entry; + + if (!zram_dedup_enabled(zram)) + return; + + new->checksum = checksum; + hash = &zram->hash[checksum % zram->hash_size]; + rb_root = &hash->rb_root; + + spin_lock(&hash->lock); + rb_node = &rb_root->rb_node; + while (*rb_node) { + parent = *rb_node; + entry = rb_entry(parent, struct zram_entry, rb_node); + if (checksum < entry->checksum) + rb_node = &parent->rb_left; + else if (checksum > entry->checksum) + rb_node = &parent->rb_right; + else + rb_node = &parent->rb_left; + } + + rb_link_node(&new->rb_node, parent, rb_node); + rb_insert_color(&new->rb_node, rb_root); + spin_unlock(&hash->lock); +} + +static bool zram_dedup_match(struct zram *zram, struct zram_entry *entry, + unsigned char *mem) +{ + bool match = false; + unsigned char *cmem; + struct zcomp_strm *zstrm; + + cmem = zs_map_object(zram->mem_pool, entry->handle, ZS_MM_RO); + if (entry->len == PAGE_SIZE) { + match = !memcmp(mem, cmem, PAGE_SIZE); + } else { + zstrm = zcomp_stream_get(zram->comp); + if (!zcomp_decompress(zstrm, cmem, entry->len, zstrm->buffer)) + match = !memcmp(mem, zstrm->buffer, PAGE_SIZE); + zcomp_stream_put(zram->comp); + } + zs_unmap_object(zram->mem_pool, entry->handle); + + return match; +} + +static unsigned long zram_dedup_put(struct zram *zram, + struct zram_entry *entry) +{ + struct zram_hash *hash; + u32 checksum; + + checksum = entry->checksum; + hash = &zram->hash[checksum % zram->hash_size]; + + spin_lock(&hash->lock); + + entry->refcount--; + if (!entry->refcount) + rb_erase(&entry->rb_node, &hash->rb_root); + else + atomic64_sub(entry->len, &zram->stats.dup_data_size); + + spin_unlock(&hash->lock); + + return entry->refcount; +} + +static struct zram_entry *__zram_dedup_get(struct zram *zram, + struct zram_hash *hash, unsigned char *mem, + struct zram_entry *entry) +{ + struct zram_entry *tmp, *prev = NULL; + struct rb_node *rb_node; + + /* find left-most entry with same checksum */ + while ((rb_node = rb_prev(&entry->rb_node))) { + tmp = rb_entry(rb_node, struct zram_entry, rb_node); + if (tmp->checksum != entry->checksum) + break; + + entry = tmp; + } + +again: + entry->refcount++; + atomic64_add(entry->len, &zram->stats.dup_data_size); + spin_unlock(&hash->lock); + + if (prev) + zram_entry_free(zram, prev); + + if (zram_dedup_match(zram, entry, mem)) + return entry; + + spin_lock(&hash->lock); + tmp = NULL; + rb_node = rb_next(&entry->rb_node); + if (rb_node) + tmp = rb_entry(rb_node, struct zram_entry, rb_node); + + if (tmp && (tmp->checksum == entry->checksum)) { + prev = entry; + entry = tmp; + goto again; + } + + spin_unlock(&hash->lock); + zram_entry_free(zram, entry); + + return NULL; +} + +static struct zram_entry *zram_dedup_get(struct zram *zram, + unsigned char *mem, u32 checksum) +{ + struct zram_hash *hash; + struct zram_entry *entry; + struct rb_node *rb_node; + + hash = &zram->hash[checksum % zram->hash_size]; + + spin_lock(&hash->lock); + rb_node = hash->rb_root.rb_node; + while (rb_node) { + entry = rb_entry(rb_node, struct zram_entry, rb_node); + if (checksum == entry->checksum) + return __zram_dedup_get(zram, hash, mem, entry); + + if (checksum < entry->checksum) + rb_node = rb_node->rb_left; + else + rb_node = rb_node->rb_right; + } + spin_unlock(&hash->lock); + + return NULL; +} + +struct zram_entry *zram_dedup_find(struct zram *zram, struct page *page, + u32 *checksum) +{ + void *mem; + struct zram_entry *entry; + + if (!zram_dedup_enabled(zram)) + return NULL; + + mem = kmap_atomic(page); + *checksum = zram_dedup_checksum(mem); + + entry = zram_dedup_get(zram, mem, *checksum); + kunmap_atomic(mem); + + return entry; +} + +void zram_dedup_init_entry(struct zram *zram, struct zram_entry *entry, + unsigned long handle, unsigned int len) +{ + if (!zram_dedup_enabled(zram)) + return; + + entry->handle = handle; + entry->refcount = 1; + entry->len = len; +} + +bool zram_dedup_put_entry(struct zram *zram, struct zram_entry *entry) +{ + if (!zram_dedup_enabled(zram)) + return true; + + if (zram_dedup_put(zram, entry)) + return false; + + return true; +} + +int zram_dedup_init(struct zram *zram, size_t num_pages) +{ + int i; + struct zram_hash *hash; + + if (!zram_dedup_enabled(zram)) + return 0; + + zram->hash_size = num_pages >> ZRAM_HASH_SHIFT; + zram->hash_size = min_t(size_t, ZRAM_HASH_SIZE_MAX, zram->hash_size); + zram->hash_size = max_t(size_t, ZRAM_HASH_SIZE_MIN, zram->hash_size); + zram->hash = vzalloc(zram->hash_size * sizeof(struct zram_hash)); + if (!zram->hash) { + pr_err("Error allocating zram entry hash\n"); + return -ENOMEM; + } + + for (i = 0; i < zram->hash_size; i++) { + hash = &zram->hash[i]; + spin_lock_init(&hash->lock); + hash->rb_root = RB_ROOT; + } + + return 0; +} + +void zram_dedup_fini(struct zram *zram) +{ + vfree(zram->hash); + zram->hash = NULL; + zram->hash_size = 0; +} diff --git a/drivers/block/zram/zram_dedup.h b/drivers/block/zram/zram_dedup.h new file mode 100644 index 0000000000000000000000000000000000000000..8ab267b0b9567638baac86630a1062ddcae37aa0 --- /dev/null +++ b/drivers/block/zram/zram_dedup.h @@ -0,0 +1,45 @@ +#ifndef _ZRAM_DEDUP_H_ +#define _ZRAM_DEDUP_H_ + +struct zram; +struct zram_entry; + +#ifdef CONFIG_ZRAM_DEDUP + +u64 zram_dedup_dup_size(struct zram *zram); +u64 zram_dedup_meta_size(struct zram *zram); + +void zram_dedup_insert(struct zram *zram, struct zram_entry *new, + u32 checksum); +struct zram_entry *zram_dedup_find(struct zram *zram, struct page *page, + u32 *checksum); + +void zram_dedup_init_entry(struct zram *zram, struct zram_entry *entry, + unsigned long handle, unsigned int len); +bool zram_dedup_put_entry(struct zram *zram, struct zram_entry *entry); + +int zram_dedup_init(struct zram *zram, size_t num_pages); +void zram_dedup_fini(struct zram *zram); +#else + +static inline u64 zram_dedup_dup_size(struct zram *zram) { return 0; } +static inline u64 zram_dedup_meta_size(struct zram *zram) { return 0; } + +static inline void zram_dedup_insert(struct zram *zram, struct zram_entry *new, + u32 checksum) { } +static inline struct zram_entry *zram_dedup_find(struct zram *zram, + struct page *page, u32 *checksum) { return NULL; } + +static inline void zram_dedup_init_entry(struct zram *zram, + struct zram_entry *entry, unsigned long handle, + unsigned int len) { } +static inline bool zram_dedup_put_entry(struct zram *zram, + struct zram_entry *entry) { return true; } + +static inline int zram_dedup_init(struct zram *zram, + size_t num_pages) { return 0; } +static inline void zram_dedup_fini(struct zram *zram) { } + +#endif + +#endif /* _ZRAM_DEDUP_H_ */ diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 4d0a776f70ab3ce2e2ecc718b76917f17732816d..e3f8000bfbaf363a30654f4737430e66209c6232 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -314,6 +314,7 @@ static ssize_t backing_dev_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { char *file_name; + size_t sz; struct file *backing_dev = NULL; struct inode *inode; struct address_space *mapping; @@ -334,7 +335,11 @@ static ssize_t backing_dev_store(struct device *dev, goto out; } - strlcpy(file_name, buf, len); + strlcpy(file_name, buf, PATH_MAX); + /* ignore trailing newline */ + sz = strlen(file_name); + if (sz > 0 && file_name[sz - 1] == '\n') + file_name[sz - 1] = 0x00; backing_dev = filp_open(file_name, O_RDWR|O_LARGEFILE, 0); if (IS_ERR(backing_dev)) { @@ -659,6 +664,41 @@ static ssize_t comp_algorithm_store(struct device *dev, return len; } +static ssize_t use_dedup_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool val; + struct zram *zram = dev_to_zram(dev); + + down_read(&zram->init_lock); + val = zram->use_dedup; + up_read(&zram->init_lock); + + return scnprintf(buf, PAGE_SIZE, "%d\n", (int)val); +} + +#ifdef CONFIG_ZRAM_DEDUP +static ssize_t use_dedup_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + int val; + struct zram *zram = dev_to_zram(dev); + + if (kstrtoint(buf, 10, &val) || (val != 0 && val != 1)) + return -EINVAL; + + down_write(&zram->init_lock); + if (init_done(zram)) { + up_write(&zram->init_lock); + pr_info("Can't change dedup usage for initialized device\n"); + return -EBUSY; + } + zram->use_dedup = val; + up_write(&zram->init_lock); + return len; +} +#endif + static ssize_t compact_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { @@ -715,14 +755,16 @@ static ssize_t mm_stat_show(struct device *dev, max_used = atomic_long_read(&zram->stats.max_used_pages); ret = scnprintf(buf, PAGE_SIZE, - "%8llu %8llu %8llu %8lu %8ld %8llu %8lu\n", + "%8llu %8llu %8llu %8lu %8ld %8llu %8lu %8llu %8llu\n", orig_size << PAGE_SHIFT, (u64)atomic64_read(&zram->stats.compr_data_size), mem_used << PAGE_SHIFT, zram->limit_pages << PAGE_SHIFT, max_used << PAGE_SHIFT, (u64)atomic64_read(&zram->stats.same_pages), - pool_stats.pages_compacted); + pool_stats.pages_compacted, + zram_dedup_dup_size(zram), + zram_dedup_meta_size(zram)); up_read(&zram->init_lock); return ret; @@ -749,6 +791,15 @@ static DEVICE_ATTR_RO(io_stat); static DEVICE_ATTR_RO(mm_stat); static DEVICE_ATTR_RO(debug_stat); +static unsigned long zram_entry_handle(struct zram *zram, + struct zram_entry *entry) +{ + if (zram_dedup_enabled(zram)) + return entry->handle; + else + return (unsigned long)entry; +} + static void zram_slot_lock(struct zram *zram, u32 index) { bit_spin_lock(ZRAM_ACCESS, &zram->table[index].value); @@ -763,26 +814,41 @@ static struct zram_entry *zram_entry_alloc(struct zram *zram, unsigned int len, gfp_t flags) { struct zram_entry *entry; + unsigned long handle; - entry = kzalloc(sizeof(*entry), - flags & ~(__GFP_HIGHMEM|__GFP_MOVABLE|__GFP_CMA)); - if (!entry) + handle = zs_malloc(zram->mem_pool, len, flags); + if (!handle) return NULL; - entry->handle = zs_malloc(zram->mem_pool, len, flags); - if (!entry->handle) { - kfree(entry); + if (!zram_dedup_enabled(zram)) + return (struct zram_entry *)handle; + + entry = kzalloc(sizeof(*entry), + flags & ~(__GFP_HIGHMEM|__GFP_MOVABLE|__GFP_CMA)); + if (!entry) { + zs_free(zram->mem_pool, handle); return NULL; } + zram_dedup_init_entry(zram, entry, handle, len); + atomic64_add(sizeof(*entry), &zram->stats.meta_data_size); + return entry; } -static inline void zram_entry_free(struct zram *zram, - struct zram_entry *entry) +void zram_entry_free(struct zram *zram, struct zram_entry *entry) { - zs_free(zram->mem_pool, entry->handle); + if (!zram_dedup_put_entry(zram, entry)) + return; + + zs_free(zram->mem_pool, zram_entry_handle(zram, entry)); + + if (!zram_dedup_enabled(zram)) + return; + kfree(entry); + + atomic64_sub(sizeof(*entry), &zram->stats.meta_data_size); } static void zram_meta_free(struct zram *zram, u64 disksize) @@ -795,6 +861,7 @@ static void zram_meta_free(struct zram *zram, u64 disksize) zram_free_page(zram, index); zs_destroy_pool(zram->mem_pool); + zram_dedup_fini(zram); vfree(zram->table); } @@ -813,6 +880,12 @@ static bool zram_meta_alloc(struct zram *zram, u64 disksize) return false; } + if (zram_dedup_init(zram, num_pages)) { + vfree(zram->table); + zs_destroy_pool(zram->mem_pool); + return false; + } + return true; } @@ -898,7 +971,8 @@ static int __zram_bvec_read(struct zram *zram, struct page *page, u32 index, size = zram_get_obj_size(zram, index); - src = zs_map_object(zram->mem_pool, entry->handle, ZS_MM_RO); + src = zs_map_object(zram->mem_pool, + zram_entry_handle(zram, entry), ZS_MM_RO); if (size == PAGE_SIZE) { dst = kmap_atomic(page); memcpy(dst, src, PAGE_SIZE); @@ -912,7 +986,7 @@ static int __zram_bvec_read(struct zram *zram, struct page *page, u32 index, kunmap_atomic(dst); zcomp_stream_put(zram->comp); } - zs_unmap_object(zram->mem_pool, entry->handle); + zs_unmap_object(zram->mem_pool, zram_entry_handle(zram, entry)); zram_slot_unlock(zram, index); /* Should NEVER happen. Return bio error if it does. */ @@ -965,6 +1039,7 @@ static int __zram_bvec_write(struct zram *zram, struct bio_vec *bvec, void *src, *dst, *mem; struct zcomp_strm *zstrm; struct page *page = bvec->bv_page; + u32 checksum; unsigned long element = 0; enum zram_pageflags flags = 0; bool allow_wb = true; @@ -979,6 +1054,12 @@ static int __zram_bvec_write(struct zram *zram, struct bio_vec *bvec, } kunmap_atomic(mem); + entry = zram_dedup_find(zram, page, &checksum); + if (entry) { + comp_len = entry->len; + goto out; + } + compress_again: zstrm = zcomp_stream_get(zram->comp); src = kmap_atomic(page); @@ -1048,7 +1129,8 @@ static int __zram_bvec_write(struct zram *zram, struct bio_vec *bvec, return -ENOMEM; } - dst = zs_map_object(zram->mem_pool, entry->handle, ZS_MM_WO); + dst = zs_map_object(zram->mem_pool, + zram_entry_handle(zram, entry), ZS_MM_WO); src = zstrm->buffer; if (comp_len == PAGE_SIZE) @@ -1058,8 +1140,9 @@ static int __zram_bvec_write(struct zram *zram, struct bio_vec *bvec, kunmap_atomic(src); zcomp_stream_put(zram->comp); - zs_unmap_object(zram->mem_pool, entry->handle); + zs_unmap_object(zram->mem_pool, zram_entry_handle(zram, entry)); atomic64_add(comp_len, &zram->stats.compr_data_size); + zram_dedup_insert(zram, entry, checksum); out: /* * Free memory associated with this sector @@ -1485,6 +1568,11 @@ static DEVICE_ATTR_RW(comp_algorithm); #ifdef CONFIG_ZRAM_WRITEBACK static DEVICE_ATTR_RW(backing_dev); #endif +#ifdef CONFIG_ZRAM_DEDUP +static DEVICE_ATTR_RW(use_dedup); +#else +static DEVICE_ATTR_RO(use_dedup); +#endif static struct attribute *zram_disk_attrs[] = { &dev_attr_disksize.attr, @@ -1498,6 +1586,7 @@ static struct attribute *zram_disk_attrs[] = { #ifdef CONFIG_ZRAM_WRITEBACK &dev_attr_backing_dev.attr, #endif + &dev_attr_use_dedup.attr, &dev_attr_io_stat.attr, &dev_attr_mm_stat.attr, &dev_attr_debug_stat.attr, diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h index 355ce657abb126abf9b2776719274f5ac20bca54..52dcd39e7b073837cb47f2bc3cb88beb660519df 100644 --- a/drivers/block/zram/zram_drv.h +++ b/drivers/block/zram/zram_drv.h @@ -18,8 +18,10 @@ #include #include #include +#include #include "zcomp.h" +#include "zram_dedup.h" /*-- Configurable parameters */ @@ -71,6 +73,10 @@ enum zram_pageflags { /*-- Data structures */ struct zram_entry { + struct rb_node rb_node; + u32 len; + u32 checksum; + unsigned long refcount; unsigned long handle; }; @@ -95,6 +101,16 @@ struct zram_stats { atomic64_t pages_stored; /* no. of pages currently stored */ atomic_long_t max_used_pages; /* no. of maximum pages stored */ atomic64_t writestall; /* no. of write slow paths */ + atomic64_t dup_data_size; /* + * compressed size of pages + * duplicated + */ + atomic64_t meta_data_size; /* size of zram_entries */ +}; + +struct zram_hash { + spinlock_t lock; + struct rb_root rb_root; }; struct zram { @@ -102,6 +118,8 @@ struct zram { struct zs_pool *mem_pool; struct zcomp *comp; struct gendisk *disk; + struct zram_hash *hash; + size_t hash_size; /* Prevent concurrent execution of device init */ struct rw_semaphore init_lock; /* @@ -120,6 +138,7 @@ struct zram { * zram is claimed so open request will be failed */ bool claim; /* Protected by bdev->bd_mutex */ + bool use_dedup; #ifdef CONFIG_ZRAM_WRITEBACK struct file *backing_dev; struct block_device *bdev; @@ -129,4 +148,15 @@ struct zram { spinlock_t bitmap_lock; #endif }; + +static inline bool zram_dedup_enabled(struct zram *zram) +{ +#ifdef CONFIG_ZRAM_DEDUP + return zram->use_dedup; +#else + return false; +#endif +} + +void zram_entry_free(struct zram *zram, struct zram_entry *entry); #endif diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 9520173e2776222624ace972dfc61a9181b0f64a..189615012860f868a32f3638578756f893edc47f 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -146,6 +146,7 @@ config BT_HCIUART_LL config BT_HCIUART_3WIRE bool "Three-wire UART (H5) protocol support" depends on BT_HCIUART + depends on BT_HCIUART_SERDEV help The HCI Three-wire UART Transport Layer makes it possible to user the Bluetooth HCI over a serial port interface. The HCI diff --git a/drivers/bluetooth/btfm_slim.h b/drivers/bluetooth/btfm_slim.h index fc653fde261210d2075ffd062e0b42ecafb77461..5a89416749607fe4ace6fa87eaff7d06bd24a76f 100644 --- a/drivers/bluetooth/btfm_slim.h +++ b/drivers/bluetooth/btfm_slim.h @@ -41,6 +41,7 @@ enum { BTFM_BT_SCO_SLIM_TX, BTFM_BT_SCO_A2DP_SLIM_RX, BTFM_BT_SPLIT_A2DP_SLIM_RX, + BTFM_BT_SPLIT_A2DP_SLIM_TX, BTFM_SLIM_NUM_CODEC_DAIS }; @@ -69,6 +70,7 @@ struct btfmslim { uint32_t num_rx_port; uint32_t num_tx_port; uint32_t sample_rate; + int dai_id; struct btfmslim_ch *rx_chs; struct btfmslim_ch *tx_chs; diff --git a/drivers/bluetooth/btfm_slim_codec.c b/drivers/bluetooth/btfm_slim_codec.c index b85e9123ee81c2aca71d397d95dc8fd22c7b8a1f..1186f74fbf88480b7e6b9c2168c95d60d0ab36e3 100644 --- a/drivers/bluetooth/btfm_slim_codec.c +++ b/drivers/bluetooth/btfm_slim_codec.c @@ -129,6 +129,10 @@ static void btfm_slim_dai_shutdown(struct snd_pcm_substream *substream, ch = btfmslim->rx_chs; rxport = 1; break; + case BTFM_BT_SPLIT_A2DP_SLIM_TX: + ch = btfmslim->tx_chs; + rxport = 0; + break; case BTFM_SLIM_NUM_CODEC_DAIS: default: BTFMSLIM_ERR("dai->id is invalid:%d", dai->id); @@ -155,10 +159,13 @@ static int btfm_slim_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { + struct btfmslim *btfmslim = dai->dev->platform_data; + BTFMSLIM_DBG("dai->name = %s DAI-ID %x rate %d num_ch %d", dai->name, dai->id, params_rate(params), params_channels(params)); + btfmslim->dai_id = dai->id; return 0; } @@ -193,6 +200,10 @@ static int btfm_slim_dai_prepare(struct snd_pcm_substream *substream, ch = btfmslim->rx_chs; rxport = 1; break; + case BTFM_BT_SPLIT_A2DP_SLIM_TX: + ch = btfmslim->tx_chs; + rxport = 0; + break; case BTFM_SLIM_NUM_CODEC_DAIS: default: BTFMSLIM_ERR("dai->id is invalid:%d", dai->id); @@ -310,6 +321,20 @@ static int btfm_slim_dai_get_channel_map(struct snd_soc_dai *dai, *tx_num = num; *rx_num = 0; break; + case BTFM_BT_SPLIT_A2DP_SLIM_TX: + if (!tx_slot || !tx_num) { + BTFMSLIM_ERR("Invalid tx_slot %p or tx_num %p", + tx_slot, tx_num); + return -EINVAL; + } + ch = btfmslim->tx_chs; + if (!ch) + return -EINVAL; + slot = tx_slot; + *rx_slot = 0; + *tx_num = num; + *rx_num = 0; + break; case BTFM_BT_SCO_A2DP_SLIM_RX: case BTFM_BT_SPLIT_A2DP_SLIM_RX: if (!rx_slot || !rx_num) { @@ -431,6 +456,22 @@ static struct snd_soc_dai_driver btfmslim_dai[] = { }, .ops = &btfmslim_dai_ops, }, + { /* Bluetooth Split A2DP sink: bt -> adsp */ + .name = "btfm_bt_split_a2dp_slim_tx", + .id = BTFM_BT_SPLIT_A2DP_SLIM_TX, + .capture = { + .stream_name = "A2DP Tx Capture", + /* 8 KHz or 16 KHz */ + .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 + | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */ + .rate_max = 96000, + .rate_min = 44100, + .channels_min = 1, + .channels_max = 1, + }, + .ops = &btfmslim_dai_ops, + }, }; static struct snd_soc_codec_driver btfmslim_codec = { diff --git a/drivers/bluetooth/btfm_slim_wcn3990.c b/drivers/bluetooth/btfm_slim_wcn3990.c index 8cebb5064ad7494ed884905f03d9e72b83992539..1eabce217f4f2268c0cb4826bc205281bef07887 100644 --- a/drivers/bluetooth/btfm_slim_wcn3990.c +++ b/drivers/bluetooth/btfm_slim_wcn3990.c @@ -30,6 +30,8 @@ struct btfmslim_ch wcn3990_txport[] = { .port = CHRK_SB_PGD_PORT_TX2_FM}, {.id = BTFM_BT_SCO_SLIM_TX, .name = "SCO_Tx", .port = CHRK_SB_PGD_PORT_TX_SCO}, + {.id = BTFM_BT_SPLIT_A2DP_SLIM_TX, .name = "A2DP_Tx", + .port = CHRK_SB_PGD_PORT_TX_A2DP}, {.id = BTFM_SLIM_NUM_CODEC_DAIS, .name = "", .port = BTFM_SLIM_PGD_PORT_LAST}, }; @@ -69,12 +71,10 @@ int btfm_slim_chrk_hw_init(struct btfmslim *btfmslim) return ret; } -static inline int is_fm_port(uint8_t port_num) +static inline int is_fm_port(struct btfmslim *btfmslim) { - if (port_num == CHRK_SB_PGD_PORT_TX1_FM || - port_num == CHRKVER3_SB_PGD_PORT_TX1_FM || - port_num == CHRKVER3_SB_PGD_PORT_TX2_FM || - port_num == CHRK_SB_PGD_PORT_TX2_FM) + BTFMSLIM_INFO("dai id is %d", btfmslim->dai_id); + if (btfmslim->dai_id == BTFM_FM_SLIM_TX) return 1; else return 0; @@ -139,7 +139,7 @@ int btfm_slim_chrk_enable_port(struct btfmslim *btfmslim, uint8_t port_num, /* txport */ /* Multiple Channel Setting */ - if (is_fm_port(port_num)) { + if (is_fm_port(btfmslim)) { if (port_num == CHRKVER3_SB_PGD_PORT_TX1_FM) reg_val = (0x1 << CHRKVER3_SB_PGD_PORT_TX1_FM); else if (port_num == CHRKVER3_SB_PGD_PORT_TX2_FM) @@ -167,6 +167,18 @@ int btfm_slim_chrk_enable_port(struct btfmslim *btfmslim, uint8_t port_num, ret, reg); goto error; } + } else if (port_num == CHRK_SB_PGD_PORT_TX_A2DP) { + /* SCO Tx */ + reg_val = 0x1 << CHRK_SB_PGD_PORT_TX_A2DP; + reg = CHRK_SB_PGD_TX_PORTn_MULTI_CHNL_0(port_num); + BTFMSLIM_DBG("writing reg_val (%d) to reg(%x)", + reg_val, reg); + ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD); + if (ret) { + BTFMSLIM_ERR("failed to write (%d) reg 0x%x", + ret, reg); + goto error; + } } /* Enable Tx port hw auto recovery for underrun or overrun error */ @@ -189,7 +201,7 @@ int btfm_slim_chrk_enable_port(struct btfmslim *btfmslim, uint8_t port_num, else en = CHRK_SB_PGD_PORT_DISABLE; - if (is_fm_port(port_num)) + if (is_fm_port(btfmslim)) reg_val = en | CHRK_SB_PGD_PORT_WM_L8; else if (port_num == CHRK_SB_PGD_PORT_TX_SCO) reg_val = enable ? en | CHRK_SB_PGD_PORT_WM_L1 : en; @@ -199,6 +211,9 @@ int btfm_slim_chrk_enable_port(struct btfmslim *btfmslim, uint8_t port_num, if (enable && port_num == CHRK_SB_PGD_PORT_TX_SCO) BTFMSLIM_INFO("programming SCO Tx with reg_val %d to reg 0x%x", reg_val, reg); + else if (enable && port_num == CHRK_SB_PGD_PORT_TX_A2DP) + BTFMSLIM_INFO("programming A2DP Tx with reg_val %d to reg 0x%x", + reg_val, reg); ret = btfm_slim_write(btfmslim, reg, 1, ®_val, IFD); if (ret) diff --git a/drivers/bluetooth/btfm_slim_wcn3990.h b/drivers/bluetooth/btfm_slim_wcn3990.h index 694fe75168f7ea1187bc5e470a16ec8bd9e07395..ceacb299c36f4f96f2a2a3e376fe158e3306a4c1 100644 --- a/drivers/bluetooth/btfm_slim_wcn3990.h +++ b/drivers/bluetooth/btfm_slim_wcn3990.h @@ -82,6 +82,7 @@ #define CHRKVER3_SB_PGD_PORT_TX2_FM 5 #define CHRK_SB_PGD_PORT_RX_SCO 16 #define CHRK_SB_PGD_PORT_RX_A2P 17 +#define CHRK_SB_PGD_PORT_TX_A2DP 2 enum { QCA_CHEROKEE_SOC_ID_0100 = 0x40010100, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 819521d5895e1dd3b78105d0b7f52612358ed982..b8dffe937f4ff7df519ed2e106d6216cd910ffc3 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -375,6 +375,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x7392, 0xa611), .driver_info = BTUSB_REALTEK }, /* Additional Realtek 8723DE Bluetooth devices */ + { USB_DEVICE(0x0bda, 0xb009), .driver_info = BTUSB_REALTEK }, { USB_DEVICE(0x2ff8, 0xb011), .driver_info = BTUSB_REALTEK }, /* Additional Realtek 8821AE Bluetooth devices */ diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 6aef3bde10d70e3cfa3643869c3e38c45d9faf25..c823914b3a80a0ce550dff8244df835b23ec66ec 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -115,12 +115,12 @@ static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu) struct sk_buff *skb = hu->tx_skb; if (!skb) { - read_lock(&hu->proto_lock); + percpu_down_read(&hu->proto_lock); if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) skb = hu->proto->dequeue(hu); - read_unlock(&hu->proto_lock); + percpu_up_read(&hu->proto_lock); } else { hu->tx_skb = NULL; } @@ -130,7 +130,14 @@ static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu) int hci_uart_tx_wakeup(struct hci_uart *hu) { - read_lock(&hu->proto_lock); + /* This may be called in an IRQ context, so we can't sleep. Therefore + * we try to acquire the lock only, and if that fails we assume the + * tty is being closed because that is the only time the write lock is + * acquired. If, however, at some point in the future the write lock + * is also acquired in other situations, then this must be revisited. + */ + if (!percpu_down_read_trylock(&hu->proto_lock)) + return 0; if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) goto no_schedule; @@ -145,7 +152,7 @@ int hci_uart_tx_wakeup(struct hci_uart *hu) schedule_work(&hu->write_work); no_schedule: - read_unlock(&hu->proto_lock); + percpu_up_read(&hu->proto_lock); return 0; } @@ -247,12 +254,12 @@ static int hci_uart_flush(struct hci_dev *hdev) tty_ldisc_flush(tty); tty_driver_flush_buffer(tty); - read_lock(&hu->proto_lock); + percpu_down_read(&hu->proto_lock); if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) hu->proto->flush(hu); - read_unlock(&hu->proto_lock); + percpu_up_read(&hu->proto_lock); return 0; } @@ -275,15 +282,15 @@ static int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s: type %d len %d", hdev->name, hci_skb_pkt_type(skb), skb->len); - read_lock(&hu->proto_lock); + percpu_down_read(&hu->proto_lock); if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) { - read_unlock(&hu->proto_lock); + percpu_up_read(&hu->proto_lock); return -EUNATCH; } hu->proto->enqueue(hu, skb); - read_unlock(&hu->proto_lock); + percpu_up_read(&hu->proto_lock); hci_uart_tx_wakeup(hu); @@ -486,7 +493,7 @@ static int hci_uart_tty_open(struct tty_struct *tty) INIT_WORK(&hu->init_ready, hci_uart_init_work); INIT_WORK(&hu->write_work, hci_uart_write_work); - rwlock_init(&hu->proto_lock); + percpu_init_rwsem(&hu->proto_lock); /* Flush any pending characters in the driver */ tty_driver_flush_buffer(tty); @@ -503,7 +510,6 @@ static void hci_uart_tty_close(struct tty_struct *tty) { struct hci_uart *hu = tty->disc_data; struct hci_dev *hdev; - unsigned long flags; BT_DBG("tty %p", tty); @@ -518,9 +524,9 @@ static void hci_uart_tty_close(struct tty_struct *tty) hci_uart_close(hdev); if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) { - write_lock_irqsave(&hu->proto_lock, flags); + percpu_down_write(&hu->proto_lock); clear_bit(HCI_UART_PROTO_READY, &hu->flags); - write_unlock_irqrestore(&hu->proto_lock, flags); + percpu_up_write(&hu->proto_lock); cancel_work_sync(&hu->write_work); @@ -582,10 +588,10 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, if (!hu || tty != hu->tty) return; - read_lock(&hu->proto_lock); + percpu_down_read(&hu->proto_lock); if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) { - read_unlock(&hu->proto_lock); + percpu_up_read(&hu->proto_lock); return; } @@ -593,7 +599,7 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, * tty caller */ hu->proto->recv(hu, data, count); - read_unlock(&hu->proto_lock); + percpu_up_read(&hu->proto_lock); if (hu->hdev) hu->hdev->stat.byte_rx += count; diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c index b725ac4f7ff67dfaab9745668e9839d0a0783de5..52e6d4d1608e3265a1aa68ae8ed1b41fcc9bb49b 100644 --- a/drivers/bluetooth/hci_serdev.c +++ b/drivers/bluetooth/hci_serdev.c @@ -304,6 +304,7 @@ int hci_uart_register_device(struct hci_uart *hu, hci_set_drvdata(hdev, hu); INIT_WORK(&hu->write_work, hci_uart_write_work); + percpu_init_rwsem(&hu->proto_lock); /* Only when vendor specific setup callback is provided, consider * the manufacturer information valid. This avoids filling in the diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index d9cd95d81149b1f9dc43506edcd02b9a86b03526..66e8c68e4607d72e462ea0c093dcefd6fb4636d5 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -87,7 +87,7 @@ struct hci_uart { struct work_struct write_work; const struct hci_uart_proto *proto; - rwlock_t proto_lock; /* Stop work for proto close */ + struct percpu_rw_semaphore proto_lock; /* Stop work for proto close */ void *priv; struct sk_buff *tx_skb; diff --git a/drivers/bus/mhi/core/mhi_init.c b/drivers/bus/mhi/core/mhi_init.c index 76960cef1a7056e86cd06b6f35713e375f07327a..8c399a5f4b9c345a6f4a434ca60c2a2299ceaa4b 100644 --- a/drivers/bus/mhi/core/mhi_init.c +++ b/drivers/bus/mhi/core/mhi_init.c @@ -1313,14 +1313,19 @@ static int mhi_driver_probe(struct device *dev) bool auto_start = false; int ret; + /* bring device out of lpm */ + ret = mhi_device_get_sync(mhi_dev); + if (ret) + return ret; + ret = -EINVAL; if (ul_chan) { /* lpm notification require status_cb */ if (ul_chan->lpm_notify && !mhi_drv->status_cb) - return -EINVAL; + goto exit_probe; if (!ul_chan->offload_ch && !mhi_drv->ul_xfer_cb) - return -EINVAL; + goto exit_probe; ul_chan->xfer_cb = mhi_drv->ul_xfer_cb; mhi_dev->status_cb = mhi_drv->status_cb; @@ -1329,10 +1334,10 @@ static int mhi_driver_probe(struct device *dev) if (dl_chan) { if (dl_chan->lpm_notify && !mhi_drv->status_cb) - return -EINVAL; + goto exit_probe; if (!dl_chan->offload_ch && !mhi_drv->dl_xfer_cb) - return -EINVAL; + goto exit_probe; mhi_event = &mhi_cntrl->mhi_event[dl_chan->er_index]; @@ -1342,7 +1347,7 @@ static int mhi_driver_probe(struct device *dev) * cb whenever there are pending data */ if (mhi_event->cl_manage && !mhi_drv->status_cb) - return -EINVAL; + goto exit_probe; dl_chan->xfer_cb = mhi_drv->dl_xfer_cb; @@ -1356,6 +1361,9 @@ static int mhi_driver_probe(struct device *dev) if (!ret && auto_start) mhi_prepare_for_transfer(mhi_dev); +exit_probe: + mhi_device_put(mhi_dev); + return ret; } diff --git a/drivers/bus/mhi/devices/mhi_netdev.c b/drivers/bus/mhi/devices/mhi_netdev.c index c6ec258d43cbad53b24d288b23db517dbb9424ff..11b757ed0f4738c5a5a642eaf199cb47a4748374 100644 --- a/drivers/bus/mhi/devices/mhi_netdev.c +++ b/drivers/bus/mhi/devices/mhi_netdev.c @@ -89,31 +89,20 @@ struct mhi_stats { u32 alloc_failed; }; -/* important: do not exceed sk_buf->cb (48 bytes) */ -struct mhi_skb_priv { - void *buf; - size_t size; - struct mhi_netdev *mhi_netdev; -}; - struct mhi_netdev { int alias; struct mhi_device *mhi_dev; spinlock_t rx_lock; bool enabled; rwlock_t pm_lock; /* state change lock */ - int (*rx_queue)(struct mhi_netdev *, gfp_t); struct work_struct alloc_work; int wake; - struct sk_buff_head rx_allocated; - u32 mru; const char *interface_name; struct napi_struct napi; struct net_device *ndev; struct sk_buff *frag_skb; - bool recycle_buf; struct mhi_stats stats; struct dentry *dentry; @@ -149,23 +138,10 @@ static __be16 mhi_netdev_ip_type_trans(struct sk_buff *skb) return protocol; } -static void mhi_netdev_skb_destructor(struct sk_buff *skb) -{ - struct mhi_skb_priv *skb_priv = (struct mhi_skb_priv *)(skb->cb); - struct mhi_netdev *mhi_netdev = skb_priv->mhi_netdev; - - skb->data = skb->head; - skb_reset_tail_pointer(skb); - skb->len = 0; - MHI_ASSERT(skb->data != skb_priv->buf, "incorrect buf"); - skb_queue_tail(&mhi_netdev->rx_allocated, skb); -} - static int mhi_netdev_alloc_skb(struct mhi_netdev *mhi_netdev, gfp_t gfp_t) { u32 cur_mru = mhi_netdev->mru; struct mhi_device *mhi_dev = mhi_netdev->mhi_dev; - struct mhi_skb_priv *skb_priv; int ret; struct sk_buff *skb; int no_tre = mhi_get_no_free_descriptors(mhi_dev, DMA_FROM_DEVICE); @@ -183,18 +159,11 @@ static int mhi_netdev_alloc_skb(struct mhi_netdev *mhi_netdev, gfp_t gfp_t) goto error_queue; } - skb_priv = (struct mhi_skb_priv *)skb->cb; - skb_priv->buf = skb->data; - skb_priv->size = cur_mru; - skb_priv->mhi_netdev = mhi_netdev; skb->dev = mhi_netdev->ndev; - if (mhi_netdev->recycle_buf) - skb->destructor = mhi_netdev_skb_destructor; - spin_lock_bh(&mhi_netdev->rx_lock); - ret = mhi_queue_transfer(mhi_dev, DMA_FROM_DEVICE, skb, - skb_priv->size, MHI_EOT); + ret = mhi_queue_transfer(mhi_dev, DMA_FROM_DEVICE, skb, cur_mru, + MHI_EOT); spin_unlock_bh(&mhi_netdev->rx_lock); if (ret) { @@ -209,7 +178,6 @@ static int mhi_netdev_alloc_skb(struct mhi_netdev *mhi_netdev, gfp_t gfp_t) return 0; error_queue: - skb->destructor = NULL; read_unlock_bh(&mhi_netdev->pm_lock); dev_kfree_skb_any(skb); @@ -240,66 +208,6 @@ static void mhi_netdev_alloc_work(struct work_struct *work) MSG_LOG("Exit with status:%d retry:%d\n", ret, retry); } -/* we will recycle buffers */ -static int mhi_netdev_skb_recycle(struct mhi_netdev *mhi_netdev, gfp_t gfp_t) -{ - struct mhi_device *mhi_dev = mhi_netdev->mhi_dev; - int no_tre; - int ret = 0; - struct sk_buff *skb; - struct mhi_skb_priv *skb_priv; - - read_lock_bh(&mhi_netdev->pm_lock); - if (!mhi_netdev->enabled) { - read_unlock_bh(&mhi_netdev->pm_lock); - return -EIO; - } - - no_tre = mhi_get_no_free_descriptors(mhi_dev, DMA_FROM_DEVICE); - - spin_lock_bh(&mhi_netdev->rx_lock); - while (no_tre) { - skb = skb_dequeue(&mhi_netdev->rx_allocated); - - /* no free buffers to recycle, reschedule work */ - if (!skb) { - ret = -ENOMEM; - goto error_queue; - } - - skb_priv = (struct mhi_skb_priv *)(skb->cb); - ret = mhi_queue_transfer(mhi_dev, DMA_FROM_DEVICE, skb, - skb_priv->size, MHI_EOT); - - /* failed to queue buffer */ - if (ret) { - MSG_ERR("Failed to queue skb, ret:%d\n", ret); - skb_queue_tail(&mhi_netdev->rx_allocated, skb); - goto error_queue; - } - - no_tre--; - } - -error_queue: - spin_unlock_bh(&mhi_netdev->rx_lock); - read_unlock_bh(&mhi_netdev->pm_lock); - - return ret; -} - -static void mhi_netdev_dealloc(struct mhi_netdev *mhi_netdev) -{ - struct sk_buff *skb; - - skb = skb_dequeue(&mhi_netdev->rx_allocated); - while (skb) { - skb->destructor = NULL; - kfree_skb(skb); - skb = skb_dequeue(&mhi_netdev->rx_allocated); - } -} - static int mhi_netdev_poll(struct napi_struct *napi, int budget) { struct net_device *dev = napi->dev; @@ -329,7 +237,7 @@ static int mhi_netdev_poll(struct napi_struct *napi, int budget) } /* queue new buffers */ - ret = mhi_netdev->rx_queue(mhi_netdev, GFP_ATOMIC); + ret = mhi_netdev_alloc_skb(mhi_netdev, GFP_ATOMIC); if (ret == -ENOMEM) { MSG_LOG("out of tre, queuing bg worker\n"); mhi_netdev->stats.alloc_failed++; @@ -390,12 +298,9 @@ static int mhi_netdev_xmit(struct sk_buff *skb, struct net_device *dev) struct mhi_netdev *mhi_netdev = mhi_netdev_priv->mhi_netdev; struct mhi_device *mhi_dev = mhi_netdev->mhi_dev; int res = 0; - struct mhi_skb_priv *tx_priv; MSG_VERB("Entered\n"); - tx_priv = (struct mhi_skb_priv *)(skb->cb); - tx_priv->mhi_netdev = mhi_netdev; read_lock_bh(&mhi_netdev->pm_lock); if (unlikely(!mhi_netdev->enabled)) { @@ -448,10 +353,9 @@ static int mhi_netdev_ioctl_extended(struct net_device *dev, struct ifreq *ifr) ext_cmd.u.data, mhi_dev->mtu); return -EINVAL; } - if (!mhi_netdev->recycle_buf) { - MSG_LOG("MRU change request to 0x%x\n", ext_cmd.u.data); - mhi_netdev->mru = ext_cmd.u.data; - } + + MSG_LOG("MRU change request to 0x%x\n", ext_cmd.u.data); + mhi_netdev->mru = ext_cmd.u.data; break; case RMNET_IOCTL_GET_SUPPORTED_FEATURES: ext_cmd.u.data = 0; @@ -611,8 +515,6 @@ static int mhi_netdev_enable_iface(struct mhi_netdev *mhi_netdev) MSG_ERR("Network device registration failed\n"); goto net_dev_reg_fail; } - - skb_queue_head_init(&mhi_netdev->rx_allocated); } write_lock_irq(&mhi_netdev->pm_lock); @@ -625,25 +527,6 @@ static int mhi_netdev_enable_iface(struct mhi_netdev *mhi_netdev) if (ret) schedule_work(&mhi_netdev->alloc_work); - /* if we recycle prepare one more set */ - if (mhi_netdev->recycle_buf) - for (; no_tre >= 0; no_tre--) { - struct sk_buff *skb = alloc_skb(mhi_netdev->mru, - GFP_KERNEL); - struct mhi_skb_priv *skb_priv; - - if (!skb) - break; - - skb_priv = (struct mhi_skb_priv *)skb->cb; - skb_priv->buf = skb->data; - skb_priv->size = mhi_netdev->mru; - skb_priv->mhi_netdev = mhi_netdev; - skb->dev = mhi_netdev->ndev; - skb->destructor = mhi_netdev_skb_destructor; - skb_queue_tail(&mhi_netdev->rx_allocated, skb); - } - napi_enable(&mhi_netdev->napi); MSG_LOG("Exited.\n"); @@ -731,11 +614,7 @@ static void mhi_netdev_xfer_dl_cb(struct mhi_device *mhi_dev, mhi_netdev->frag_skb) { ret = mhi_netdev_process_fragment(mhi_netdev, skb); - /* recycle the skb */ - if (mhi_netdev->recycle_buf) - mhi_netdev_skb_destructor(skb); - else - dev_kfree_skb(skb); + dev_kfree_skb(skb); if (ret) return; @@ -791,9 +670,6 @@ static int mhi_netdev_debugfs_trigger_reset(void *data, u64 val) /* disable all hardware channels */ mhi_unprepare_from_transfer(mhi_dev); - /* clean up all alocated buffers */ - mhi_netdev_dealloc(mhi_netdev); - MSG_LOG("Restarting iface\n"); ret = mhi_netdev_enable_iface(mhi_netdev); @@ -905,7 +781,6 @@ static void mhi_netdev_remove(struct mhi_device *mhi_dev) napi_disable(&mhi_netdev->napi); netif_napi_del(&mhi_netdev->napi); - mhi_netdev_dealloc(mhi_netdev); unregister_netdev(mhi_netdev->ndev); free_netdev(mhi_netdev->ndev); flush_work(&mhi_netdev->alloc_work); @@ -946,11 +821,6 @@ static int mhi_netdev_probe(struct mhi_device *mhi_dev, if (ret) mhi_netdev->interface_name = mhi_netdev_driver.driver.name; - mhi_netdev->recycle_buf = of_property_read_bool(of_node, - "mhi,recycle-buf"); - mhi_netdev->rx_queue = mhi_netdev->recycle_buf ? - mhi_netdev_skb_recycle : mhi_netdev_alloc_skb; - spin_lock_init(&mhi_netdev->rx_lock); rwlock_init(&mhi_netdev->pm_lock); INIT_WORK(&mhi_netdev->alloc_work, mhi_netdev_alloc_work); diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index bfc566d3f31a40cf5b89d9284b2538644af68dee..8cfa10ab7abcb8cb0da9a9a62d7080b60f81683f 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -2542,7 +2542,7 @@ static int cdrom_ioctl_drive_status(struct cdrom_device_info *cdi, if (!CDROM_CAN(CDC_SELECT_DISC) || (arg == CDSL_CURRENT || arg == CDSL_NONE)) return cdi->ops->drive_status(cdi, CDSL_CURRENT); - if (((int)arg >= cdi->capacity)) + if (arg >= cdi->capacity) return -EINVAL; return cdrom_slot_status(cdi, arg); } diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index d6e7f8c947448f309527c0cc93645822fac9f71d..e5673cf70aa2e4b2c977bbc64a4d14ae182f866b 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -272,6 +272,7 @@ struct fastrpc_channel_ctx { struct completion workport; struct notifier_block nb; struct mutex smd_mutex; + struct mutex rpmsg_mutex; int sesscount; int ssrcount; void *handle; @@ -759,7 +760,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; @@ -767,6 +768,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); @@ -1781,16 +1787,21 @@ static int fastrpc_invoke_send(struct smq_invoke_ctx *ctx, if (fl->ssrcount != channel_ctx->ssrcount) { err = -ECONNRESET; + mutex_unlock(&channel_ctx->smd_mutex); goto bail; } + mutex_unlock(&channel_ctx->smd_mutex); + + mutex_lock(&channel_ctx->rpmsg_mutex); VERIFY(err, !IS_ERR_OR_NULL(channel_ctx->rpdev)); if (err) { err = -ECONNRESET; + mutex_unlock(&channel_ctx->rpmsg_mutex); goto bail; } err = rpmsg_send(channel_ctx->rpdev->ept, (void *)msg, sizeof(*msg)); + mutex_unlock(&channel_ctx->rpmsg_mutex); bail: - mutex_unlock(&channel_ctx->smd_mutex); return err; } @@ -1810,6 +1821,7 @@ static void fastrpc_init(struct fastrpc_apps *me) /* All channels are secure by default except CDSP */ me->channel[i].secure = SECURE_CHANNEL; mutex_init(&me->channel[i].smd_mutex); + mutex_init(&me->channel[i].rpmsg_mutex); } /* Set CDSP channel to non secure */ me->channel[CDSP_DOMAIN_ID].secure = NON_SECURE_CHANNEL; @@ -2216,6 +2228,9 @@ static int fastrpc_release_current_dsp_process(struct fastrpc_file *fl) ioctl.crc = NULL; VERIFY(err, 0 == (err = fastrpc_internal_invoke(fl, FASTRPC_MODE_PARALLEL, 1, &ioctl))); + if (err) + pr_err("adsprpc: %s: releasing DSP process failed for %s, returned 0x%x", + __func__, current->comm, err); bail: return err; } @@ -2672,9 +2687,9 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev) VERIFY(err, cid >= 0 && cid < NUM_CHANNELS); if (err) goto bail; - mutex_lock(&gcinfo[cid].smd_mutex); + mutex_lock(&gcinfo[cid].rpmsg_mutex); gcinfo[cid].rpdev = rpdev; - mutex_unlock(&gcinfo[cid].smd_mutex); + mutex_unlock(&gcinfo[cid].rpmsg_mutex); pr_info("adsprpc: %s: opened rpmsg channel for %s\n", __func__, gcinfo[cid].subsys); bail: @@ -2706,9 +2721,9 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev) VERIFY(err, cid >= 0 && cid < NUM_CHANNELS); if (err) goto bail; - mutex_lock(&gcinfo[cid].smd_mutex); + mutex_lock(&gcinfo[cid].rpmsg_mutex); gcinfo[cid].rpdev = NULL; - mutex_unlock(&gcinfo[cid].smd_mutex); + mutex_unlock(&gcinfo[cid].rpmsg_mutex); fastrpc_notify_drivers(me, cid); pr_info("adsprpc: %s: closed rpmsg channel of %s\n", __func__, gcinfo[cid].subsys); @@ -2990,6 +3005,15 @@ static int fastrpc_channel_open(struct fastrpc_file *fl) if (err) return err; + mutex_lock(&me->channel[cid].rpmsg_mutex); + VERIFY(err, NULL != me->channel[cid].rpdev); + if (err) { + err = -ENOTCONN; + mutex_unlock(&me->channel[cid].rpmsg_mutex); + goto bail; + } + mutex_unlock(&me->channel[cid].rpmsg_mutex); + mutex_lock(&me->channel[cid].smd_mutex); if (me->channel[cid].ssrcount != me->channel[cid].prevssrcount) { @@ -2997,16 +3021,13 @@ static int fastrpc_channel_open(struct fastrpc_file *fl) VERIFY(err, 0); if (err) { err = -ENOTCONN; + mutex_unlock(&me->channel[cid].smd_mutex); goto bail; } } } fl->ssrcount = me->channel[cid].ssrcount; - VERIFY(err, NULL != me->channel[cid].rpdev); - if (err) { - err = -ENOTCONN; - goto bail; - } + if (cid == ADSP_DOMAIN_ID && me->channel[cid].ssrcount != me->channel[cid].prevssrcount) { mutex_lock(&fl->map_mutex); @@ -3017,9 +3038,9 @@ static int fastrpc_channel_open(struct fastrpc_file *fl) me->channel[cid].prevssrcount = me->channel[cid].ssrcount; } + mutex_unlock(&me->channel[cid].smd_mutex); bail: - mutex_unlock(&me->channel[cid].smd_mutex); return err; } diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c index f71e57f9c435ffd5c794b432a946eefe262deb95..d8214ae2cdb27e6963a1f0ac5d53955b86694191 100644 --- a/drivers/char/diag/diag_debugfs.c +++ b/drivers/char/diag/diag_debugfs.c @@ -38,6 +38,7 @@ #include "diag_ipc_logging.h" #define DEBUG_BUF_SIZE 4096 +#define CMD_SIZE 10 static struct dentry *diag_dbgfs_dent; static int diag_dbgfs_table_index; static int diag_dbgfs_mempool_index; @@ -689,15 +690,14 @@ static ssize_t diag_dbgfs_read_rpmsginfo(struct file *file, char __user *ubuf, static ssize_t diag_dbgfs_write_debug(struct file *fp, const char __user *buf, size_t count, loff_t *ppos) { - const int size = 10; - unsigned char cmd[size]; + unsigned char cmd[CMD_SIZE]; long value = 0; int len = 0; if (count < 1) return -EINVAL; - len = (count < (size - 1)) ? count : size - 1; + len = (count < (CMD_SIZE - 1)) ? count : CMD_SIZE - 1; if (copy_from_user(cmd, buf, len)) return -EFAULT; diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index 4fd21d8327cc8ad54d2d773119fb80829fe69dd0..1cb57603b632f5b56fa876c3a3a92310559eaf45 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.c @@ -202,7 +202,7 @@ static void diag_send_log_mask_update(uint8_t peripheral, int equip_id) } memcpy(buf, &ctrl_pkt, header_len); - if (mask_size > 0 && mask_size <= LOG_MASK_SIZE) + if (mask_size > 0) memcpy(buf + header_len, mask->ptr, mask_size); mutex_unlock(&mask->lock); @@ -304,7 +304,7 @@ static void diag_send_event_mask_update(uint8_t peripheral) buf = temp; } } - if (num_bytes > 0 && num_bytes < mask_info->mask_len) + if (num_bytes > 0) memcpy(buf + sizeof(header), mask_info->ptr, num_bytes); else { pr_err("diag: num_bytes(%d) is not satisfying length condition\n", diff --git a/drivers/char/diag/diag_usb.c b/drivers/char/diag/diag_usb.c index b3e86d8ad8621b68fdff70ee6b4472b60e5e5c0d..5a8fd3e19f80a557f3af42be8cfe63ec277f6a65 100644 --- a/drivers/char/diag/diag_usb.c +++ b/drivers/char/diag/diag_usb.c @@ -520,12 +520,16 @@ int diag_usb_write(int id, unsigned char *buf, int len, int ctxt) usb_info = &diag_usb[id]; + if (!atomic_read(&usb_info->connected)) + return -ENOTCONN; + if (len > usb_info->max_size) { DIAG_LOG(DIAG_DEBUG_MUX, "len: %d, max_size: %d\n", len, usb_info->max_size); return diag_usb_write_ext(usb_info, buf, len, ctxt); } + spin_lock_irqsave(&usb_info->write_lock, flags); req = diagmem_alloc(driver, sizeof(struct diag_request), usb_info->mempool); if (!req) { @@ -534,9 +538,12 @@ int diag_usb_write(int id, unsigned char *buf, int len, int ctxt) * trying to write more buffers than the max supported by * this particualar diag USB channel at any given instance, * or the previous write ptrs are stuck in the USB layer. + * Remove the buffer entry from the usb buf table for this case. */ pr_err_ratelimited("diag: In %s, cannot retrieve USB write ptrs for USB channel %s\n", __func__, usb_info->name); + diag_usb_buf_tbl_remove(usb_info, buf); + spin_unlock_irqrestore(&usb_info->write_lock, flags); return -ENOMEM; } @@ -549,10 +556,10 @@ int diag_usb_write(int id, unsigned char *buf, int len, int ctxt) pr_debug_ratelimited("diag: USB ch %s is not connected\n", usb_info->name); diagmem_free(driver, req, usb_info->mempool); + spin_unlock_irqrestore(&usb_info->write_lock, flags); return -ENODEV; } - spin_lock_irqsave(&usb_info->write_lock, flags); if (diag_usb_buf_tbl_add(usb_info, buf, len, ctxt)) { DIAG_LOG(DIAG_DEBUG_MUX, "ERR! unable to add buf %pK to table\n", diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index 767b81fbb502009a7457ac5dcf83a4b74bc28a7d..f55a5d2765be362639fe89e3067aa69d146f4406 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -1852,7 +1852,8 @@ static int diag_switch_logging(struct diag_logging_mode_param_t *param) "Switch logging to %d mask:%0x\n", new_mode, peripheral_mask); /* Update to take peripheral_mask */ - if (new_mode != DIAG_MEMORY_DEVICE_MODE) { + if (new_mode != DIAG_MEMORY_DEVICE_MODE || + new_mode != DIAG_MULTI_MODE) { diag_update_real_time_vote(DIAG_PROC_MEMORY_DEVICE, MODE_REALTIME, ALL_PROC); } else { @@ -1860,8 +1861,9 @@ static int diag_switch_logging(struct diag_logging_mode_param_t *param) ALL_PROC); } - if (!(new_mode == DIAG_MEMORY_DEVICE_MODE && - curr_mode == DIAG_USB_MODE)) { + if (!((new_mode == DIAG_MEMORY_DEVICE_MODE || + new_mode == DIAG_MULTI_MODE) && + curr_mode == DIAG_USB_MODE)) { queue_work(driver->diag_real_time_wq, &driver->diag_real_time_work); } @@ -3250,13 +3252,13 @@ static int diag_user_process_apps_data(const char __user *buf, int len, mutex_lock(&apps_data_mutex); mutex_lock(&driver->hdlc_disable_mutex); hdlc_disabled = driver->p_hdlc_disabled[APPS_DATA]; + mutex_unlock(&driver->hdlc_disable_mutex); if (hdlc_disabled) ret = diag_process_apps_data_non_hdlc(user_space_data, len, pkt_type); else ret = diag_process_apps_data_hdlc(user_space_data, len, pkt_type); - mutex_unlock(&driver->hdlc_disable_mutex); mutex_unlock(&apps_data_mutex); diagmem_free(driver, user_space_data, mempool); diff --git a/drivers/char/diag/diagfwd_bridge.c b/drivers/char/diag/diagfwd_bridge.c index 55a16b2a26e1a6d59af95270f01666012065244f..cd7c084e511708ace6db2beac2cf85ba6c01a901 100644 --- a/drivers/char/diag/diagfwd_bridge.c +++ b/drivers/char/diag/diagfwd_bridge.c @@ -29,6 +29,7 @@ #endif #include "diagfwd_mhi.h" #include "diag_dci.h" +#include "diag_ipc_logging.h" #ifdef CONFIG_MHI_BUS #define diag_mdm_init diag_mhi_init diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c index 7f98b2fc0e2301541569a794322a91081124d84a..13cb75553595cd3c62543e7b7ddd75103f50f6eb 100644 --- a/drivers/char/diag/diagfwd_cntl.c +++ b/drivers/char/diag/diagfwd_cntl.c @@ -1124,15 +1124,22 @@ static inline void diag_send_diag_mode_update_remote(int token, int real_time) void diag_real_time_work_fn(struct work_struct *work) { int temp_real_time = MODE_REALTIME, i, j; - uint8_t send_update = 1; + uint8_t send_update = 1, peripheral = 0; /* * If any peripheral in the local processor is in either threshold or * circular buffering mode, don't send the real time mode control * packet. */ - for (i = 0; i < NUM_PERIPHERALS; i++) { - if (!driver->feature[i].peripheral_buffering) + for (i = 0; i < NUM_MD_SESSIONS; i++) { + peripheral = i; + if (peripheral == APPS_DATA) + continue; + + if (peripheral > NUM_PERIPHERALS) + peripheral = diag_search_peripheral_by_pd(i); + + if (!driver->feature[peripheral].peripheral_buffering) continue; switch (driver->buffering_mode[i].mode) { case DIAG_BUFFERING_MODE_THRESHOLD: diff --git a/drivers/char/diag/diagfwd_mhi.c b/drivers/char/diag/diagfwd_mhi.c index 6c83706940ef8891051e4148f90073e6ae8d352b..ce732961f6a0284fe1a321876d723b6846bc57b6 100644 --- a/drivers/char/diag/diagfwd_mhi.c +++ b/drivers/char/diag/diagfwd_mhi.c @@ -83,7 +83,6 @@ struct diag_mhi_info diag_mhi[NUM_MHI_DEV] = { static int mhi_buf_tbl_add(struct diag_mhi_info *mhi_info, int type, void *buf, int len) { - unsigned long flags; struct diag_mhi_buf_tbl_t *item; struct diag_mhi_ch_t *ch = NULL; @@ -103,16 +102,14 @@ static int mhi_buf_tbl_add(struct diag_mhi_info *mhi_info, int type, return -EINVAL; } - item = kzalloc(sizeof(struct diag_mhi_buf_tbl_t), GFP_KERNEL); + item = kzalloc(sizeof(*item), GFP_ATOMIC); if (!item) return -ENOMEM; kmemleak_not_leak(item); - spin_lock_irqsave(&ch->lock, flags); item->buf = buf; item->len = len; list_add_tail(&item->link, &ch->buf_tbl); - spin_unlock_irqrestore(&ch->lock, flags); return 0; } @@ -166,7 +163,9 @@ static void mhi_buf_tbl_clear(struct diag_mhi_info *mhi_info) unsigned long flags; struct list_head *start, *temp; struct diag_mhi_buf_tbl_t *item = NULL; + struct diag_mhi_buf_tbl_t *tp = NULL, *tp_temp = NULL; struct diag_mhi_ch_t *ch = NULL; + unsigned char *buf; if (!mhi_info || !mhi_info->enabled) return; @@ -180,9 +179,17 @@ static void mhi_buf_tbl_clear(struct diag_mhi_info *mhi_info) item = list_entry(start, struct diag_mhi_buf_tbl_t, link); list_del(&item->link); + buf = item->buf; + list_for_each_entry_safe(tp, tp_temp, + &mhi_info->read_done_list, link) { + if (tp->buf == buf) { + list_del(&tp->link); + kfree(tp); + tp = NULL; + } + } diagmem_free(driver, item->buf, mhi_info->mempool); kfree(item); - } spin_unlock_irqrestore(&ch->lock, flags); } @@ -348,9 +355,9 @@ static void mhi_read_done_work_fn(struct work_struct *work) do { if (!(atomic_read(&(mhi_info->read_ch.opened)))) break; - spin_lock_irqsave(&mhi_info->lock, flags); + spin_lock_irqsave(&mhi_info->read_ch.lock, flags); if (list_empty(&mhi_info->read_done_list)) { - spin_unlock_irqrestore(&mhi_info->lock, flags); + spin_unlock_irqrestore(&mhi_info->read_ch.lock, flags); break; } tp = list_first_entry(&mhi_info->read_done_list, @@ -359,7 +366,7 @@ static void mhi_read_done_work_fn(struct work_struct *work) buf = tp->buf; len = tp->len; kfree(tp); - spin_unlock_irqrestore(&mhi_info->lock, flags); + spin_unlock_irqrestore(&mhi_info->read_ch.lock, flags); if (!buf) break; DIAG_LOG(DIAG_DEBUG_BRIDGE, @@ -373,12 +380,15 @@ static void mhi_read_done_work_fn(struct work_struct *work) if ((atomic_read(&(mhi_info->read_ch.opened)))) { err = diag_remote_dev_read_done(mhi_info->dev_id, buf, len); - if (err) + if (err) { mhi_buf_tbl_remove(mhi_info, TYPE_MHI_READ_CH, buf, len); + break; + } } else { mhi_buf_tbl_remove(mhi_info, TYPE_MHI_READ_CH, buf, len); + break; } } while (buf); } @@ -400,22 +410,26 @@ static void mhi_read_work_fn(struct work_struct *work) do { if (!(atomic_read(&(read_ch->opened)))) break; + spin_lock_irqsave(&read_ch->lock, flags); buf = diagmem_alloc(driver, DIAG_MDM_BUF_SIZE, mhi_info->mempool); - spin_unlock_irqrestore(&read_ch->lock, flags); - if (!buf) + if (!buf) { + spin_unlock_irqrestore(&read_ch->lock, flags); break; + } err = mhi_buf_tbl_add(mhi_info, TYPE_MHI_READ_CH, buf, DIAG_MDM_BUF_SIZE); - if (err) + if (err) { + spin_unlock_irqrestore(&read_ch->lock, flags); goto fail; + } DIAG_LOG(DIAG_DEBUG_BRIDGE, "queueing a read buf %pK, ch: %s\n", buf, mhi_info->name); - spin_lock_irqsave(&read_ch->lock, flags); + err = mhi_queue_transfer(mhi_info->mhi_dev, DMA_FROM_DEVICE, buf, DIAG_MDM_BUF_SIZE, mhi_flags); spin_unlock_irqrestore(&read_ch->lock, flags); @@ -475,12 +489,12 @@ static int mhi_write(int id, unsigned char *buf, int len, int ctxt) return -EIO; } + spin_lock_irqsave(&ch->lock, flags); err = mhi_buf_tbl_add(&diag_mhi[id], TYPE_MHI_WRITE_CH, buf, len); if (err) goto fail; - spin_lock_irqsave(&ch->lock, flags); err = mhi_queue_transfer(diag_mhi[id].mhi_dev, DMA_TO_DEVICE, buf, len, mhi_flags); spin_unlock_irqrestore(&ch->lock, flags); @@ -533,9 +547,11 @@ static void diag_mhi_read_cb(struct mhi_device *mhi_dev, struct mhi_result *result) { struct diag_mhi_info *mhi_info = NULL; - struct diag_mhi_buf_tbl_t *tp; + struct diag_mhi_buf_tbl_t *item = NULL; + struct diag_mhi_buf_tbl_t *tp = NULL, *temp = NULL; unsigned long flags; void *buf = NULL; + uint8_t queue_read = 0; if (!mhi_dev) return; @@ -548,18 +564,29 @@ static void diag_mhi_read_cb(struct mhi_device *mhi_dev, return; if (atomic_read(&mhi_info->read_ch.opened) && result->transaction_status != -ENOTCONN) { + spin_lock_irqsave(&mhi_info->read_ch.lock, flags); tp = kmalloc(sizeof(*tp), GFP_ATOMIC); if (!tp) { DIAG_LOG(DIAG_DEBUG_BRIDGE, "no mem for list\n"); + spin_unlock_irqrestore(&mhi_info->read_ch.lock, flags); return; } - tp->buf = buf; - tp->len = result->bytes_xferd; - spin_lock_irqsave(&mhi_info->lock, flags); - list_add_tail(&tp->link, &mhi_info->read_done_list); - spin_unlock_irqrestore(&mhi_info->lock, flags); - queue_work(mhi_info->mhi_wq, &(mhi_info->read_done_work)); + list_for_each_entry_safe(item, temp, + &mhi_info->read_ch.buf_tbl, link) { + if (item->buf == buf) { + tp->buf = buf; + tp->len = result->bytes_xferd; + list_add_tail(&tp->link, + &mhi_info->read_done_list); + queue_read = 1; + break; + } + } + spin_unlock_irqrestore(&mhi_info->read_ch.lock, flags); + if (queue_read) + queue_work(mhi_info->mhi_wq, + &(mhi_info->read_done_work)); } else { mhi_buf_tbl_remove(mhi_info, TYPE_MHI_READ_CH, buf, result->bytes_xferd); diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c index 772b05bed3fe20e6edd0c16cc62e24721ae2afd6..669b6e30ba7b626f8a394a0c0d64d9544892cb62 100644 --- a/drivers/char/diag/diagfwd_peripheral.c +++ b/drivers/char/diag/diagfwd_peripheral.c @@ -1304,9 +1304,6 @@ int diagfwd_channel_close(struct diagfwd_info *fwd_info) if (!fwd_info) return -EIO; - if (fwd_info->type == TYPE_CNTL) - flush_workqueue(driver->cntl_wq); - mutex_lock(&driver->diagfwd_channel_mutex[fwd_info->peripheral]); fwd_info->ch_open = 0; if (fwd_info && fwd_info->c_ops && fwd_info->c_ops->close) diff --git a/drivers/char/diag/diagfwd_socket.c b/drivers/char/diag/diagfwd_socket.c index f959a332ccd3ef6ddd045e12141551c50d2f3d06..b0f5d2625535381571b23c3cd8079dbeb067823f 100644 --- a/drivers/char/diag/diagfwd_socket.c +++ b/drivers/char/diag/diagfwd_socket.c @@ -243,7 +243,6 @@ static int restart_notifier_cb(struct notifier_block *this, unsigned long code, return NOTIFY_DONE; } - mutex_lock(&driver->diag_notifier_mutex); DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "%s: ssr for processor %d ('%s')\n", __func__, notifier->processor, notifier->name); @@ -253,7 +252,12 @@ static int restart_notifier_cb(struct notifier_block *this, unsigned long code, case SUBSYS_BEFORE_SHUTDOWN: DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "diag: %s: SUBSYS_BEFORE_SHUTDOWN\n", __func__); - bootup_req[notifier->processor] = PEPIPHERAL_SSR_DOWN; + mutex_lock(&driver->diag_notifier_mutex); + bootup_req[notifier->processor] = PERIPHERAL_SSR_DOWN; + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: bootup_req[%s] = %d\n", + notifier->name, (int)bootup_req[notifier->processor]); + mutex_unlock(&driver->diag_notifier_mutex); break; case SUBSYS_AFTER_SHUTDOWN: @@ -269,11 +273,20 @@ static int restart_notifier_cb(struct notifier_block *this, unsigned long code, case SUBSYS_AFTER_POWERUP: DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "diag: %s: SUBSYS_AFTER_POWERUP\n", __func__); + mutex_lock(&driver->diag_notifier_mutex); if (!bootup_req[notifier->processor]) { - bootup_req[notifier->processor] = PEPIPHERAL_SSR_DOWN; + bootup_req[notifier->processor] = PERIPHERAL_SSR_DOWN; + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: bootup_req[%s] = %d\n", + notifier->name, (int)bootup_req[notifier->processor]); + mutex_unlock(&driver->diag_notifier_mutex); break; } - bootup_req[notifier->processor] = PEPIPHERAL_SSR_UP; + bootup_req[notifier->processor] = PERIPHERAL_SSR_UP; + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: bootup_req[%s] = %d\n", + notifier->name, (int)bootup_req[notifier->processor]); + mutex_unlock(&driver->diag_notifier_mutex); break; default: @@ -281,11 +294,6 @@ static int restart_notifier_cb(struct notifier_block *this, unsigned long code, "diag: code: %lu\n", code); break; } - mutex_unlock(&driver->diag_notifier_mutex); - DIAG_LOG(DIAG_DEBUG_PERIPHERALS, - "diag: bootup_req[%s] = %d\n", - notifier->name, (int)bootup_req[notifier->processor]); - return NOTIFY_DONE; } @@ -497,13 +505,6 @@ static void __socket_close_channel(struct diag_socket_info *info) if (!info || !info->hdl) return; - if (bootup_req[info->peripheral] == PEPIPHERAL_SSR_UP) { - DIAG_LOG(DIAG_DEBUG_PERIPHERALS, - "diag: %s is up, stopping cleanup: bootup_req = %d\n", - info->name, (int)bootup_req[info->peripheral]); - return; - } - memset(&info->remote_addr, 0, sizeof(info->remote_addr)); diagfwd_channel_close(info->fwd_ctxt); @@ -621,8 +622,15 @@ static void handle_ctrl_pkt(struct diag_socket_info *info, void *buf, int len) info->name); mutex_lock(&driver->diag_notifier_mutex); - socket_close_channel(info); + if (bootup_req[info->peripheral] == PERIPHERAL_SSR_UP) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: %s is up, stopping cleanup: bootup_req = %d\n", + info->name, (int)bootup_req[info->peripheral]); + mutex_unlock(&driver->diag_notifier_mutex); + break; + } mutex_unlock(&driver->diag_notifier_mutex); + socket_close_channel(info); } break; case QRTR_TYPE_DEL_CLIENT: @@ -635,8 +643,15 @@ static void handle_ctrl_pkt(struct diag_socket_info *info, void *buf, int len) info->name); mutex_lock(&driver->diag_notifier_mutex); - socket_close_channel(info); + if (bootup_req[info->peripheral] == PERIPHERAL_SSR_UP) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: %s is up, stopping cleanup: bootup_req = %d\n", + info->name, (int)bootup_req[info->peripheral]); + mutex_unlock(&driver->diag_notifier_mutex); + break; + } mutex_unlock(&driver->diag_notifier_mutex); + socket_close_channel(info); } break; } @@ -741,24 +756,34 @@ static int diag_socket_read(void *ctxt, unsigned char *buf, int buf_len) qrtr_ctrl_recd += read_len; continue; } - - if (!atomic_read(&info->opened) && - info->port_type == PORT_TYPE_SERVER) { - /* - * This is the first packet from the client. Copy its - * address to the connection object. Consider this - * channel open for communication. - */ + if (info->type == TYPE_CNTL) { memcpy(&info->remote_addr, &src_addr, sizeof(src_addr)); DIAG_LOG(DIAG_DEBUG_PERIPHERALS, - "%s first client [0x%x:0x%x]\n", - info->name, src_addr.sq_node, - src_addr.sq_port); + "%s client node:port::[0x%x]:[0x%x]\n", + info->name, src_addr.sq_node, src_addr.sq_port); - if (info->ins_id == INST_ID_DCI) - atomic_set(&info->opened, 1); - else + if (!atomic_read(&info->opened)) __socket_open_channel(info); + } else { + if (!atomic_read(&info->opened) && + info->port_type == PORT_TYPE_SERVER) { + /* + * This is the first packet from the client. + * Copy its address to the connection object. + * Consider this channel open for communication. + */ + memcpy(&info->remote_addr, &src_addr, + sizeof(src_addr)); + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "%s client node:port::[0x%x]:[0x%x]\n", + info->name, src_addr.sq_node, + src_addr.sq_port); + + if (info->ins_id == INST_ID_DCI) + atomic_set(&info->opened, 1); + else + __socket_open_channel(info); + } } temp += read_len; total_recd += read_len; diff --git a/drivers/char/diag/diagfwd_socket.h b/drivers/char/diag/diagfwd_socket.h index 810bd4bb68b87f5e12a5c5ed195942df8f2a6e76..1a23fd76a7e0ca6aeec48a4e686e2c9cba63c145 100644 --- a/drivers/char/diag/diagfwd_socket.h +++ b/drivers/char/diag/diagfwd_socket.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -21,9 +21,9 @@ #define PORT_TYPE_SERVER 0 #define PORT_TYPE_CLIENT 1 -#define PEPIPHERAL_AFTER_BOOT 0 -#define PEPIPHERAL_SSR_DOWN 1 -#define PEPIPHERAL_SSR_UP 2 +#define PERIPHERAL_AFTER_BOOT 0 +#define PERIPHERAL_SSR_DOWN 1 +#define PERIPHERAL_SSR_UP 2 enum { SOCKET_MODEM, diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index 6f2eaba1cd6a60f17597d6c7426287ccc228f811..932678617dfa7e212699cdd1afde16c5e480df26 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -184,6 +184,8 @@ struct ssif_addr_info { struct device *dev; struct i2c_client *client; + struct i2c_client *added_client; + struct mutex clients_mutex; struct list_head clients; @@ -1710,15 +1712,7 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) out: if (rv) { - /* - * Note that if addr_info->client is assigned, we - * leave it. The i2c client hangs around even if we - * return a failure here, and the failure here is not - * propagated back to the i2c code. This seems to be - * design intent, strange as it may be. But if we - * don't leave it, ssif_platform_remove will not remove - * the client like it should. - */ + addr_info->client = NULL; dev_err(&client->dev, "Unable to start IPMI SSIF: %d\n", rv); kfree(ssif_info); } @@ -1737,7 +1731,8 @@ static int ssif_adapter_handler(struct device *adev, void *opaque) if (adev->type != &i2c_adapter_type) return 0; - i2c_new_device(to_i2c_adapter(adev), &addr_info->binfo); + addr_info->added_client = i2c_new_device(to_i2c_adapter(adev), + &addr_info->binfo); if (!addr_info->adapter_name) return 1; /* Only try the first I2C adapter by default. */ @@ -2018,8 +2013,8 @@ static int ssif_platform_remove(struct platform_device *dev) return 0; mutex_lock(&ssif_infos_mutex); - if (addr_info->client) - i2c_unregister_device(addr_info->client); + if (addr_info->added_client) + i2c_unregister_device(addr_info->added_client); list_del(&addr_info->link); kfree(addr_info); diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index dba5259def6038645dbe24d95f0243c0b6282443..a2070ab86c824c402d142395f19389e578e205c3 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -369,10 +369,13 @@ static int tpm_validate_command(struct tpm_chip *chip, return -EINVAL; } -static int tpm_request_locality(struct tpm_chip *chip) +static int tpm_request_locality(struct tpm_chip *chip, unsigned int flags) { int rc; + if (flags & TPM_TRANSMIT_RAW) + return 0; + if (!chip->ops->request_locality) return 0; @@ -385,10 +388,13 @@ static int tpm_request_locality(struct tpm_chip *chip) return 0; } -static void tpm_relinquish_locality(struct tpm_chip *chip) +static void tpm_relinquish_locality(struct tpm_chip *chip, unsigned int flags) { int rc; + if (flags & TPM_TRANSMIT_RAW) + return; + if (!chip->ops->relinquish_locality) return; @@ -399,6 +405,28 @@ static void tpm_relinquish_locality(struct tpm_chip *chip) chip->locality = -1; } +static int tpm_cmd_ready(struct tpm_chip *chip, unsigned int flags) +{ + if (flags & TPM_TRANSMIT_RAW) + return 0; + + if (!chip->ops->cmd_ready) + return 0; + + return chip->ops->cmd_ready(chip); +} + +static int tpm_go_idle(struct tpm_chip *chip, unsigned int flags) +{ + if (flags & TPM_TRANSMIT_RAW) + return 0; + + if (!chip->ops->go_idle) + return 0; + + return chip->ops->go_idle(chip); +} + static ssize_t tpm_try_transmit(struct tpm_chip *chip, struct tpm_space *space, u8 *buf, size_t bufsiz, @@ -423,7 +451,7 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, header->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS); header->return_code = cpu_to_be32(TPM2_RC_COMMAND_CODE | TSS2_RESMGR_TPM_RC_LAYER); - return bufsiz; + return sizeof(*header); } if (bufsiz > TPM_BUFSIZE) @@ -449,14 +477,15 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, /* Store the decision as chip->locality will be changed. */ need_locality = chip->locality == -1; - if (!(flags & TPM_TRANSMIT_RAW) && need_locality) { - rc = tpm_request_locality(chip); + if (need_locality) { + rc = tpm_request_locality(chip, flags); if (rc < 0) goto out_no_locality; } - if (chip->dev.parent) - pm_runtime_get_sync(chip->dev.parent); + rc = tpm_cmd_ready(chip, flags); + if (rc) + goto out; rc = tpm2_prepare_space(chip, space, ordinal, buf); if (rc) @@ -516,13 +545,16 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, } rc = tpm2_commit_space(chip, space, ordinal, buf, &len); + if (rc) + dev_err(&chip->dev, "tpm2_commit_space: error %d\n", rc); out: - if (chip->dev.parent) - pm_runtime_put_sync(chip->dev.parent); + rc = tpm_go_idle(chip, flags); + if (rc) + goto out; if (need_locality) - tpm_relinquish_locality(chip); + tpm_relinquish_locality(chip, flags); out_no_locality: if (chip->ops->clk_enable != NULL) diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index b83b30a3eea5ef4e2de8b60a720d7dd571d45479..4bb9b4aa9b49c11a0e24c6a8d50351575609f015 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -511,9 +511,17 @@ extern const struct file_operations tpm_fops; extern const struct file_operations tpmrm_fops; extern struct idr dev_nums_idr; +/** + * enum tpm_transmit_flags + * + * @TPM_TRANSMIT_UNLOCKED: used to lock sequence of tpm_transmit calls. + * @TPM_TRANSMIT_RAW: prevent recursive calls into setup steps + * (go idle, locality,..). Always use with UNLOCKED + * as it will fail on double locking. + */ enum tpm_transmit_flags { - TPM_TRANSMIT_UNLOCKED = BIT(0), - TPM_TRANSMIT_RAW = BIT(1), + TPM_TRANSMIT_UNLOCKED = BIT(0), + TPM_TRANSMIT_RAW = BIT(1), }; ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, diff --git a/drivers/char/tpm/tpm2-space.c b/drivers/char/tpm/tpm2-space.c index d26ea7513226c991eb3eeef3dfdbebadee8fa298..dabb2ae4e779a8cfe6360b3686380748922fe41e 100644 --- a/drivers/char/tpm/tpm2-space.c +++ b/drivers/char/tpm/tpm2-space.c @@ -39,7 +39,8 @@ static void tpm2_flush_sessions(struct tpm_chip *chip, struct tpm_space *space) for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++) { if (space->session_tbl[i]) tpm2_flush_context_cmd(chip, space->session_tbl[i], - TPM_TRANSMIT_UNLOCKED); + TPM_TRANSMIT_UNLOCKED | + TPM_TRANSMIT_RAW); } } @@ -84,7 +85,7 @@ static int tpm2_load_context(struct tpm_chip *chip, u8 *buf, tpm_buf_append(&tbuf, &buf[*offset], body_size); rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 4, - TPM_TRANSMIT_UNLOCKED, NULL); + TPM_TRANSMIT_UNLOCKED | TPM_TRANSMIT_RAW, NULL); if (rc < 0) { dev_warn(&chip->dev, "%s: failed with a system error %d\n", __func__, rc); @@ -133,7 +134,7 @@ static int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf, tpm_buf_append_u32(&tbuf, handle); rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 0, - TPM_TRANSMIT_UNLOCKED, NULL); + TPM_TRANSMIT_UNLOCKED | TPM_TRANSMIT_RAW, NULL); if (rc < 0) { dev_warn(&chip->dev, "%s: failed with a system error %d\n", __func__, rc); @@ -170,7 +171,8 @@ static void tpm2_flush_space(struct tpm_chip *chip) for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++) if (space->context_tbl[i] && ~space->context_tbl[i]) tpm2_flush_context_cmd(chip, space->context_tbl[i], - TPM_TRANSMIT_UNLOCKED); + TPM_TRANSMIT_UNLOCKED | + TPM_TRANSMIT_RAW); tpm2_flush_sessions(chip, space); } @@ -377,7 +379,8 @@ static int tpm2_map_response_header(struct tpm_chip *chip, u32 cc, u8 *rsp, return 0; out_no_slots: - tpm2_flush_context_cmd(chip, phandle, TPM_TRANSMIT_UNLOCKED); + tpm2_flush_context_cmd(chip, phandle, + TPM_TRANSMIT_UNLOCKED | TPM_TRANSMIT_RAW); dev_warn(&chip->dev, "%s: out of slots for 0x%08X\n", __func__, phandle); return -ENOMEM; @@ -465,7 +468,8 @@ static int tpm2_save_space(struct tpm_chip *chip) return rc; tpm2_flush_context_cmd(chip, space->context_tbl[i], - TPM_TRANSMIT_UNLOCKED); + TPM_TRANSMIT_UNLOCKED | + TPM_TRANSMIT_RAW); space->context_tbl[i] = ~0; } diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index bb756ad7897e7ca2b445cfa37a16a3edfd7926a6..5c7ce5aaaf6fbbb4c0696b07876ece25e2070f2d 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -137,7 +137,7 @@ static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value, } /** - * crb_go_idle - request tpm crb device to go the idle state + * __crb_go_idle - request tpm crb device to go the idle state * * @dev: crb device * @priv: crb private data @@ -151,7 +151,7 @@ static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value, * * Return: 0 always */ -static int crb_go_idle(struct device *dev, struct crb_priv *priv) +static int __crb_go_idle(struct device *dev, struct crb_priv *priv) { if ((priv->flags & CRB_FL_ACPI_START) || (priv->flags & CRB_FL_CRB_SMC_START)) @@ -166,11 +166,20 @@ static int crb_go_idle(struct device *dev, struct crb_priv *priv) dev_warn(dev, "goIdle timed out\n"); return -ETIME; } + return 0; } +static int crb_go_idle(struct tpm_chip *chip) +{ + struct device *dev = &chip->dev; + struct crb_priv *priv = dev_get_drvdata(dev); + + return __crb_go_idle(dev, priv); +} + /** - * crb_cmd_ready - request tpm crb device to enter ready state + * __crb_cmd_ready - request tpm crb device to enter ready state * * @dev: crb device * @priv: crb private data @@ -183,7 +192,7 @@ static int crb_go_idle(struct device *dev, struct crb_priv *priv) * * Return: 0 on success -ETIME on timeout; */ -static int crb_cmd_ready(struct device *dev, struct crb_priv *priv) +static int __crb_cmd_ready(struct device *dev, struct crb_priv *priv) { if ((priv->flags & CRB_FL_ACPI_START) || (priv->flags & CRB_FL_CRB_SMC_START)) @@ -201,6 +210,14 @@ static int crb_cmd_ready(struct device *dev, struct crb_priv *priv) return 0; } +static int crb_cmd_ready(struct tpm_chip *chip) +{ + struct device *dev = &chip->dev; + struct crb_priv *priv = dev_get_drvdata(dev); + + return __crb_cmd_ready(dev, priv); +} + static int __crb_request_locality(struct device *dev, struct crb_priv *priv, int loc) { @@ -393,6 +410,8 @@ static const struct tpm_class_ops tpm_crb = { .send = crb_send, .cancel = crb_cancel, .req_canceled = crb_req_canceled, + .go_idle = crb_go_idle, + .cmd_ready = crb_cmd_ready, .request_locality = crb_request_locality, .relinquish_locality = crb_relinquish_locality, .req_complete_mask = CRB_DRV_STS_COMPLETE, @@ -508,7 +527,7 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, * PTT HW bug w/a: wake up the device to access * possibly not retained registers. */ - ret = crb_cmd_ready(dev, priv); + ret = __crb_cmd_ready(dev, priv); if (ret) return ret; @@ -553,7 +572,7 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, if (!ret) priv->cmd_size = cmd_size; - crb_go_idle(dev, priv); + __crb_go_idle(dev, priv); __crb_relinquish_locality(dev, priv, 0); @@ -624,32 +643,7 @@ static int crb_acpi_add(struct acpi_device *device) chip->acpi_dev_handle = device->handle; chip->flags = TPM_CHIP_FLAG_TPM2; - rc = __crb_request_locality(dev, priv, 0); - if (rc) - return rc; - - rc = crb_cmd_ready(dev, priv); - if (rc) - goto out; - - pm_runtime_get_noresume(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - - rc = tpm_chip_register(chip); - if (rc) { - crb_go_idle(dev, priv); - pm_runtime_put_noidle(dev); - pm_runtime_disable(dev); - goto out; - } - - pm_runtime_put_sync(dev); - -out: - __crb_relinquish_locality(dev, priv, 0); - - return rc; + return tpm_chip_register(chip); } static int crb_acpi_remove(struct acpi_device *device) @@ -659,52 +653,11 @@ static int crb_acpi_remove(struct acpi_device *device) tpm_chip_unregister(chip); - pm_runtime_disable(dev); - return 0; } -static int __maybe_unused crb_pm_runtime_suspend(struct device *dev) -{ - struct tpm_chip *chip = dev_get_drvdata(dev); - struct crb_priv *priv = dev_get_drvdata(&chip->dev); - - return crb_go_idle(dev, priv); -} - -static int __maybe_unused crb_pm_runtime_resume(struct device *dev) -{ - struct tpm_chip *chip = dev_get_drvdata(dev); - struct crb_priv *priv = dev_get_drvdata(&chip->dev); - - return crb_cmd_ready(dev, priv); -} - -static int __maybe_unused crb_pm_suspend(struct device *dev) -{ - int ret; - - ret = tpm_pm_suspend(dev); - if (ret) - return ret; - - return crb_pm_runtime_suspend(dev); -} - -static int __maybe_unused crb_pm_resume(struct device *dev) -{ - int ret; - - ret = crb_pm_runtime_resume(dev); - if (ret) - return ret; - - return tpm_pm_resume(dev); -} - static const struct dev_pm_ops crb_pm = { - SET_SYSTEM_SLEEP_PM_OPS(crb_pm_suspend, crb_pm_resume) - SET_RUNTIME_PM_OPS(crb_pm_runtime_suspend, crb_pm_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(tpm_pm_suspend, tpm_pm_resume) }; static const struct acpi_device_id crb_device_ids[] = { diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c index d5b44cadac5669f46d36c48cad26c998ae931167..c619e76ce827615caa2c47bd6d6abbb368f8a416 100644 --- a/drivers/char/tpm/tpm_i2c_infineon.c +++ b/drivers/char/tpm/tpm_i2c_infineon.c @@ -117,7 +117,7 @@ static int iic_tpm_read(u8 addr, u8 *buffer, size_t len) /* Lock the adapter for the duration of the whole sequence. */ if (!tpm_dev.client->adapter->algo->master_xfer) return -EOPNOTSUPP; - i2c_lock_adapter(tpm_dev.client->adapter); + i2c_lock_bus(tpm_dev.client->adapter, I2C_LOCK_SEGMENT); if (tpm_dev.chip_type == SLB9645) { /* use a combined read for newer chips @@ -192,7 +192,7 @@ static int iic_tpm_read(u8 addr, u8 *buffer, size_t len) } out: - i2c_unlock_adapter(tpm_dev.client->adapter); + i2c_unlock_bus(tpm_dev.client->adapter, I2C_LOCK_SEGMENT); /* take care of 'guard time' */ usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI); @@ -224,7 +224,7 @@ static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len, if (!tpm_dev.client->adapter->algo->master_xfer) return -EOPNOTSUPP; - i2c_lock_adapter(tpm_dev.client->adapter); + i2c_lock_bus(tpm_dev.client->adapter, I2C_LOCK_SEGMENT); /* prepend the 'register address' to the buffer */ tpm_dev.buf[0] = addr; @@ -243,7 +243,7 @@ static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len, usleep_range(sleep_low, sleep_hi); } - i2c_unlock_adapter(tpm_dev.client->adapter); + i2c_unlock_bus(tpm_dev.client->adapter, I2C_LOCK_SEGMENT); /* take care of 'guard time' */ usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI); diff --git a/drivers/char/tpm/tpm_tis_spi.c b/drivers/char/tpm/tpm_tis_spi.c index 8ab0bd8445f6d2ba818653d642bd32d4a97b8b20..b00388fc41c8d5f13c2203dea6be15ce0b647a72 100644 --- a/drivers/char/tpm/tpm_tis_spi.c +++ b/drivers/char/tpm/tpm_tis_spi.c @@ -188,6 +188,7 @@ static const struct tpm_tis_phy_ops tpm_spi_phy_ops = { static int tpm_tis_spi_probe(struct spi_device *dev) { struct tpm_tis_spi_phy *phy; + int irq; phy = devm_kzalloc(&dev->dev, sizeof(struct tpm_tis_spi_phy), GFP_KERNEL); @@ -200,7 +201,13 @@ static int tpm_tis_spi_probe(struct spi_device *dev) if (!phy->iobuf) return -ENOMEM; - return tpm_tis_core_init(&dev->dev, &phy->priv, -1, &tpm_spi_phy_ops, + /* If the SPI device has an IRQ then use that */ + if (dev->irq > 0) + irq = dev->irq; + else + irq = -1; + + return tpm_tis_core_init(&dev->dev, &phy->priv, irq, &tpm_spi_phy_ops, NULL); } diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c index fda42aba9d4177ca2e7d653a9b639dcdad464f71..a1b5935b5b9c64d2ba634ff2fe191238f61d7b97 100644 --- a/drivers/clk/clk-fixed-factor.c +++ b/drivers/clk/clk-fixed-factor.c @@ -177,8 +177,15 @@ static struct clk *_of_fixed_factor_clk_setup(struct device_node *node) clk = clk_register_fixed_factor(NULL, clk_name, parent_name, flags, mult, div); - if (IS_ERR(clk)) + if (IS_ERR(clk)) { + /* + * If parent clock is not registered, registration would fail. + * Clear OF_POPULATED flag so that clock registration can be + * attempted again from probe function. + */ + of_node_clear_flag(node, OF_POPULATED); return clk; + } ret = of_clk_add_provider(node, of_clk_src_simple_get, clk); if (ret) { diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index b5906e95646824837d118f369cc4f7e6e999c1bc..e562c92b63c9a5836075044e95364f4444387d7c 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2889,9 +2889,10 @@ static void clock_debug_print_enabled_clocks(struct seq_file *s) struct clk_core *core; int cnt = 0; - clock_debug_output(s, 0, "Enabled clocks:\n"); + if (!mutex_trylock(&clk_debug_lock)) + return; - mutex_lock(&clk_debug_lock); + clock_debug_output(s, 0, "Enabled clocks:\n"); hlist_for_each_entry(core, &clk_debug_list, debug_node) cnt += clock_debug_print_clock(core, s); @@ -2935,30 +2936,25 @@ void clk_debug_print_hw(struct clk_core *clk, struct seq_file *f) if (!clk->ops->list_registers) return; - clk_prepare_lock(); - if (clk->ops->bus_vote) - clk->ops->bus_vote(clk->hw, true); - clk->ops->list_registers(f, clk->hw); - - if (clk->ops->bus_vote) - clk->ops->bus_vote(clk->hw, false); - clk_prepare_unlock(); } EXPORT_SYMBOL(clk_debug_print_hw); static int print_hw_show(struct seq_file *m, void *unused) { struct clk_core *c = m->private; + struct clk_core *clk; clk_prepare_lock(); - if (c->ops->bus_vote) - c->ops->bus_vote(c->hw, true); + for (clk = c; clk; clk = clk->parent) + if (clk->ops->bus_vote) + clk->ops->bus_vote(clk->hw, true); clk_debug_print_hw(c, m); - if (c->ops->bus_vote) - c->ops->bus_vote(c->hw, false); + for (clk = c; clk; clk = clk->parent) + if (clk->ops->bus_vote) + clk->ops->bus_vote(c->hw, false); clk_prepare_unlock(); return 0; @@ -3265,14 +3261,19 @@ EXPORT_SYMBOL_GPL(clk_debugfs_add_file); /* * Print the names of all enabled clocks and their parents if - * debug_suspend is set from debugfs. + * debug_suspend is set from debugfs along with print_parent flag set to 1. + * Otherwise if print_parent set to 0, print only enabled clocks + * */ -void clock_debug_print_enabled(void) +void clock_debug_print_enabled(bool print_parent) { if (likely(!debug_suspend)) return; - clock_debug_print_enabled_debug_suspend(NULL); + if (print_parent) + clock_debug_print_enabled_clocks(NULL); + else + clock_debug_print_enabled_debug_suspend(NULL); } EXPORT_SYMBOL_GPL(clock_debug_print_enabled); @@ -3599,6 +3600,7 @@ struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id, return clk; } +/* keep in sync with __clk_put */ void __clk_free_clk(struct clk *clk) { clk_prepare_lock(); @@ -4137,6 +4139,7 @@ int __clk_get(struct clk *clk) return 1; } +/* keep in sync with __clk_free_clk */ void __clk_put(struct clk *clk) { struct module *owner; @@ -4158,6 +4161,7 @@ void __clk_put(struct clk *clk) module_put(owner); + kfree_const(clk->con_id); kfree(clk); } diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h index 10fec8ad7dc9526454d2030ab66dd5fa8fe91b00..3fcdc7fc1d0cf20758eebb4875a6a6596541686c 100644 --- a/drivers/clk/clk.h +++ b/drivers/clk/clk.h @@ -23,7 +23,7 @@ struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id, void __clk_free_clk(struct clk *clk); /* Debugfs API to print the enabled clocks */ -void clock_debug_print_enabled(void); +void clock_debug_print_enabled(bool print_parent); void clk_debug_print_hw(struct clk_core *clk, struct seq_file *f); #define WARN_CLK(core, name, cond, fmt, ...) do { \ diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c index 41c08fc892b97456bf8c9d3d7740337ee051638d..5cc5ff1b4e1f5cd5e1673e7b0fc4293a5af15d54 100644 --- a/drivers/clk/imx/clk-imx6ul.c +++ b/drivers/clk/imx/clk-imx6ul.c @@ -135,6 +135,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) np = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-anatop"); base = of_iomap(np, 0); + of_node_put(np); WARN_ON(!base); clks[IMX6UL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 74c68391051f3d63fe930d4dfc7a4a044e5ee097..89089ccf32c8d44da6fab0f080c958e274392abb 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -466,3 +466,21 @@ config MSM_DEBUGCC_SDMMAGPIE Support for the debug clock controller on Qualcomm Technologies, Inc SDMMAGPIE devices. Say Y if you want to support the clock measurement functionality. + +config GCC_SDXPRAIRIE + tristate "SDXPRAIRIE Global Clock Controller" + select QCOM_GDSC + depends on COMMON_CLK_QCOM + help + Support for the global clock controller on Qualcomm Technologies, Inc + SDXPRAIRIE devices. + Say Y if you want to use peripheral devices such as UART, SPI, I2C, + USB, SD/eMMC, PCIe, etc. + +config DEBUGCC_SDXPRAIRIE + tristate "SDXPRAIRIE Debug Clock Controller" + depends on COMMON_CLK_QCOM + help + Support for the debug clock controller on Qualcomm Technologies, Inc + SDXPRAIRIE devices. + Say Y if you want to support the clock measurement functionality. diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index fba12da98c02d071ddde65ac58f89db3cf578f4a..25b3ccc4d284aa1e2cba11885e3df5aa638accee 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -21,6 +21,8 @@ obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o obj-$(CONFIG_CLOCK_CPU_OSM) += clk-cpu-osm.o obj-$(CONFIG_CLOCK_CPU_QCS405) += clk-cpu-qcs405.o +obj-$(CONFIG_DEBUGCC_SDXPRAIRIE) += debugcc-sdxprairie.o +obj-$(CONFIG_GCC_SDXPRAIRIE) += gcc-sdxprairie.o obj-$(CONFIG_IPQ_GCC_4019) += gcc-ipq4019.o obj-$(CONFIG_IPQ_GCC_806X) += gcc-ipq806x.o obj-$(CONFIG_IPQ_GCC_8074) += gcc-ipq8074.o diff --git a/drivers/clk/qcom/camcc-sdmmagpie.c b/drivers/clk/qcom/camcc-sdmmagpie.c index 50593202ec8b1980d354375f3a347032f84d9b17..d0ec6970970bd249250da875a542d6cfd13985ac 100644 --- a/drivers/clk/qcom/camcc-sdmmagpie.c +++ b/drivers/clk/qcom/camcc-sdmmagpie.c @@ -31,7 +31,7 @@ #include "clk-regmap.h" #include "common.h" #include "reset.h" -#include "vdd-level.h" +#include "vdd-level-sdmmagpie.h" #define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } @@ -188,7 +188,7 @@ static const struct parent_map cam_cc_parent_map_9[] = { }; static const char * const cam_cc_parent_names_9[] = { - "bi_tcxo", + "bi_tcxo_ao", "core_bi_pll_test_se", }; diff --git a/drivers/clk/qcom/camcc-sm8150.c b/drivers/clk/qcom/camcc-sm8150.c index 1f5bbfd8f1ddd0ca7462d9da5f0be03953df194d..e7d6885a7232c358dd0eae28dfb38386c3e60ab9 100644 --- a/drivers/clk/qcom/camcc-sm8150.c +++ b/drivers/clk/qcom/camcc-sm8150.c @@ -172,7 +172,7 @@ static const struct alpha_pll_config cam_cc_pll0_config = { .test_ctl_val = 0x00000000, .test_ctl_hi_val = 0x00000002, .test_ctl_hi1_val = 0x00000020, - .user_ctl_val = 0x00000000, + .user_ctl_val = 0x00003100, .user_ctl_hi_val = 0x00000805, .user_ctl_hi1_val = 0x000000D0, }; @@ -186,7 +186,7 @@ static const struct alpha_pll_config cam_cc_pll0_config_sm8150_v2 = { .test_ctl_val = 0x00000000, .test_ctl_hi_val = 0x00000000, .test_ctl_hi1_val = 0x00000020, - .user_ctl_val = 0x00000000, + .user_ctl_val = 0x00003100, .user_ctl_hi_val = 0x00000805, .user_ctl_hi1_val = 0x000000D0, }; @@ -214,10 +214,7 @@ static struct clk_alpha_pll cam_cc_pll0 = { }; static const struct clk_div_table post_div_table_trion_even[] = { - { 0x0, 1 }, { 0x1, 2 }, - { 0x3, 4 }, - { 0x7, 8 }, { } }; @@ -237,10 +234,7 @@ static struct clk_alpha_pll_postdiv cam_cc_pll0_out_even = { }; static const struct clk_div_table post_div_table_trion_odd[] = { - { 0x0, 1 }, { 0x3, 3 }, - { 0x5, 5 }, - { 0x7, 7 }, { } }; @@ -268,7 +262,7 @@ static const struct alpha_pll_config cam_cc_pll1_config = { .test_ctl_val = 0x00000000, .test_ctl_hi_val = 0x00000002, .test_ctl_hi1_val = 0x00000020, - .user_ctl_val = 0x00000000, + .user_ctl_val = 0x00000100, .user_ctl_hi_val = 0x00000805, .user_ctl_hi1_val = 0x000000D0, }; @@ -282,7 +276,7 @@ static const struct alpha_pll_config cam_cc_pll1_config_sm8150_v2 = { .test_ctl_val = 0x00000000, .test_ctl_hi_val = 0x00000000, .test_ctl_hi1_val = 0x00000020, - .user_ctl_val = 0x00000000, + .user_ctl_val = 0x00000100, .user_ctl_hi_val = 0x00000805, .user_ctl_hi1_val = 0x000000D0, }; @@ -333,6 +327,7 @@ static const struct alpha_pll_config cam_cc_pll2_config = { .test_ctl_val = 0x04000400, .test_ctl_hi_val = 0x00004000, .test_ctl_hi1_val = 0x00000000, + .user_ctl_val = 0x00000100, }; static struct clk_alpha_pll cam_cc_pll2 = { @@ -359,10 +354,7 @@ static struct clk_alpha_pll cam_cc_pll2 = { }; static const struct clk_div_table post_div_table_regera_main[] = { - { 0x0, 1 }, { 0x1, 2 }, - { 0x3, 4 }, - { 0x2, 8 }, { } }; @@ -390,7 +382,7 @@ static const struct alpha_pll_config cam_cc_pll3_config = { .test_ctl_val = 0x00000000, .test_ctl_hi_val = 0x00000002, .test_ctl_hi1_val = 0x00000020, - .user_ctl_val = 0x00000000, + .user_ctl_val = 0x00000100, .user_ctl_hi_val = 0x00000805, .user_ctl_hi1_val = 0x000000D0, }; @@ -404,7 +396,7 @@ static const struct alpha_pll_config cam_cc_pll3_config_sm8150_v2 = { .test_ctl_val = 0x00000000, .test_ctl_hi_val = 0x00000000, .test_ctl_hi1_val = 0x00000020, - .user_ctl_val = 0x00000000, + .user_ctl_val = 0x00000100, .user_ctl_hi_val = 0x00000805, .user_ctl_hi1_val = 0x000000D0, }; @@ -455,7 +447,7 @@ static const struct alpha_pll_config cam_cc_pll4_config = { .test_ctl_val = 0x00000000, .test_ctl_hi_val = 0x00000002, .test_ctl_hi1_val = 0x00000020, - .user_ctl_val = 0x00000000, + .user_ctl_val = 0x00000100, .user_ctl_hi_val = 0x00000805, .user_ctl_hi1_val = 0x000000D0, }; @@ -469,7 +461,7 @@ static const struct alpha_pll_config cam_cc_pll4_config_sm8150_v2 = { .test_ctl_val = 0x00000000, .test_ctl_hi_val = 0x00000000, .test_ctl_hi1_val = 0x00000020, - .user_ctl_val = 0x00000000, + .user_ctl_val = 0x00000100, .user_ctl_hi_val = 0x00000805, .user_ctl_hi1_val = 0x000000D0, }; diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index 17b6d45195704757c4db32b7720e156d585e2bce..837c62060cae7bd03bf92567e61d7fc48054eaac 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -137,6 +137,33 @@ #define AGERA_PLL_TEST_CTL_U 0x1c #define AGERA_PLL_POST_DIV_MASK 0x3 +/* LUCID PLL speficic settings and offsets */ +#define LUCID_PLL_OFF_L_VAL 0x04 +#define LUCID_PLL_OFF_CAL_L_VAL 0x08 +#define LUCID_PLL_OFF_USER_CTL 0x0c +#define LUCID_PLL_OFF_USER_CTL_U 0x10 +#define LUCID_PLL_OFF_USER_CTL_U1 0x14 +#define LUCID_PLL_OFF_CONFIG_CTL 0x18 +#define LUCID_PLL_OFF_CONFIG_CTL_U 0x1c +#define LUCID_PLL_OFF_CONFIG_CTL_U1 0x20 +#define LUCID_PLL_OFF_TEST_CTL 0x24 +#define LUCID_PLL_OFF_TEST_CTL_U 0x28 +#define LUCID_PLL_OFF_TEST_CTL_U1 0x2c +#define LUCID_PLL_OFF_STATUS 0x30 +#define LUCID_PLL_OFF_OPMODE 0x38 +#define LUCID_PLL_OFF_ALPHA_VAL 0x40 +#define LUCID_PLL_OFF_FRAC 0x40 + +#define LUCID_PLL_CAL_VAL 0x44 +#define LUCID_PLL_STANDBY 0x0 +#define LUCID_PLL_RUN 0x1 +#define LUCID_PLL_OUT_MASK 0x7 +#define LUCID_PCAL_DONE BIT(26) +#define LUCID_PLL_RATE_MARGIN 500 +#define LUCID_PLL_ACK_LATCH BIT(29) +#define LUCID_PLL_UPDATE BIT(22) +#define LUCID_PLL_HW_UPDATE_LOGIC_BYPASS BIT(23) + #define to_clk_alpha_pll(_hw) container_of(to_clk_regmap(_hw), \ struct clk_alpha_pll, clkr) @@ -453,7 +480,8 @@ static unsigned long alpha_pll_calc_rate(const struct clk_alpha_pll *pll, int alpha_bw = ALPHA_BITWIDTH; if (pll->type == TRION_PLL || pll->type == REGERA_PLL - || pll->type == FABIA_PLL || pll->type == AGERA_PLL) + || pll->type == FABIA_PLL || pll->type == AGERA_PLL + || pll->type == LUCID_PLL) alpha_bw = ALPHA_REG_16BITWIDTH; return (prate * l) + ((prate * a) >> alpha_bw); @@ -490,7 +518,8 @@ alpha_pll_round_rate(const struct clk_alpha_pll *pll, unsigned long rate, * the fractional divider. */ if (pll->type == TRION_PLL || pll->type == REGERA_PLL - || pll->type == FABIA_PLL || pll->type == AGERA_PLL) + || pll->type == FABIA_PLL || pll->type == AGERA_PLL + || pll->type == LUCID_PLL) alpha_bw = ALPHA_REG_16BITWIDTH; /* Upper ALPHA_BITWIDTH bits of Alpha */ @@ -2290,3 +2319,327 @@ const struct clk_ops clk_agera_pll_ops = { .bus_vote = clk_debug_bus_vote, }; EXPORT_SYMBOL(clk_agera_pll_ops); + +static int lucid_pll_is_enabled(struct clk_alpha_pll *pll, + struct regmap *regmap) +{ + u32 mode_regval, opmode_regval; + int ret; + + ret = regmap_read(regmap, pll->offset + PLL_MODE, &mode_regval); + ret |= regmap_read(regmap, pll->offset + LUCID_PLL_OFF_OPMODE, + &opmode_regval); + if (ret) + return 0; + + return ((opmode_regval & LUCID_PLL_RUN) && + (mode_regval & PLL_OUTCTRL)); +} + +int clk_lucid_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, + const struct alpha_pll_config *config) +{ + int ret; + + if (lucid_pll_is_enabled(pll, regmap)) { + pr_warn("PLL is already enabled. Skipping configuration.\n"); + return 0; + } + + /* + * Disable the PLL if it's already been initialized. Not doing so might + * lead to the PLL running with the old frequency configuration. + */ + if (pll->inited) { + ret = regmap_update_bits(regmap, pll->offset + PLL_MODE, + PLL_RESET_N, 0); + if (ret) + return ret; + } + + if (config->l) + regmap_write(regmap, pll->offset + LUCID_PLL_OFF_L_VAL, + config->l); + + regmap_write(regmap, pll->offset + LUCID_PLL_OFF_CAL_L_VAL, + LUCID_PLL_CAL_VAL); + + if (config->alpha) + regmap_write(regmap, pll->offset + LUCID_PLL_OFF_ALPHA_VAL, + config->alpha); + if (config->config_ctl_val) + regmap_write(regmap, pll->offset + LUCID_PLL_OFF_CONFIG_CTL, + config->config_ctl_val); + + if (config->config_ctl_hi_val) + regmap_write(regmap, pll->offset + LUCID_PLL_OFF_CONFIG_CTL_U, + config->config_ctl_hi_val); + + if (config->config_ctl_hi1_val) + regmap_write(regmap, pll->offset + LUCID_PLL_OFF_USER_CTL_U1, + config->config_ctl_hi1_val); + + if (config->post_div_mask) + regmap_update_bits(regmap, pll->offset + LUCID_PLL_OFF_USER_CTL, + config->post_div_mask, config->post_div_val); + + regmap_update_bits(regmap, pll->offset + PLL_MODE, + LUCID_PLL_HW_UPDATE_LOGIC_BYPASS, + LUCID_PLL_HW_UPDATE_LOGIC_BYPASS); + + /* Disable PLL output */ + ret = regmap_update_bits(regmap, pll->offset + PLL_MODE, + PLL_OUTCTRL, 0); + if (ret) + return ret; + + /* Set operation mode to OFF */ + regmap_write(regmap, pll->offset + LUCID_PLL_OFF_OPMODE, + LUCID_PLL_STANDBY); + + /* PLL should be in OFF mode before continuing */ + wmb(); + + /* Place the PLL in STANDBY mode */ + ret = regmap_update_bits(regmap, pll->offset + PLL_MODE, + PLL_RESET_N, PLL_RESET_N); + if (ret) + return ret; + + pll->inited = true; + return 0; +} + +static int alpha_pll_lucid_enable(struct clk_hw *hw) +{ + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + u32 val; + int ret; + + ret = regmap_read(pll->clkr.regmap, pll->offset + PLL_MODE, &val); + if (ret) + return ret; + + /* If in FSM mode, just vote for it */ + if (val & PLL_VOTE_FSM_ENA) { + ret = clk_enable_regmap(hw); + if (ret) + return ret; + return wait_for_pll_enable_active(pll); + } + + if (unlikely(!pll->inited)) { + ret = clk_lucid_pll_configure(pll, pll->clkr.regmap, + pll->config); + if (ret) { + pr_err("Failed to configure %s\n", clk_hw_get_name(hw)); + return ret; + } + } + + /* Set operation mode to RUN */ + regmap_write(pll->clkr.regmap, pll->offset + LUCID_PLL_OFF_OPMODE, + LUCID_PLL_RUN); + + ret = wait_for_pll_enable_lock(pll); + if (ret) + return ret; + + /* Enable the PLL outputs */ + ret = regmap_update_bits(pll->clkr.regmap, pll->offset + + LUCID_PLL_OFF_USER_CTL, + LUCID_PLL_OUT_MASK, LUCID_PLL_OUT_MASK); + if (ret) + return ret; + + /* Enable the global PLL outputs */ + ret = regmap_update_bits(pll->clkr.regmap, pll->offset + PLL_MODE, + PLL_OUTCTRL, PLL_OUTCTRL); + if (ret) + return ret; + + /* Ensure that the write above goes through before returning. */ + mb(); + return ret; +} + +static void alpha_pll_lucid_disable(struct clk_hw *hw) +{ + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + u32 val; + int ret; + + ret = regmap_read(pll->clkr.regmap, pll->offset + PLL_MODE, &val); + if (ret) + return; + + /* If in FSM mode, just unvote it */ + if (val & PLL_VOTE_FSM_ENA) { + clk_disable_regmap(hw); + return; + } + + /* Disable the global PLL output */ + ret = regmap_update_bits(pll->clkr.regmap, pll->offset + PLL_MODE, + PLL_OUTCTRL, 0); + if (ret) + return; + + /* Disable the PLL outputs */ + ret = regmap_update_bits(pll->clkr.regmap, pll->offset + + LUCID_PLL_OFF_USER_CTL, + LUCID_PLL_OUT_MASK, 0); + if (ret) + return; + + /* Place the PLL mode in STANDBY */ + regmap_write(pll->clkr.regmap, pll->offset + LUCID_PLL_OFF_OPMODE, + LUCID_PLL_STANDBY); + + regmap_update_bits(pll->clkr.regmap, pll->offset + PLL_MODE, + PLL_RESET_N, PLL_RESET_N); +} + +/* + * The Lucid PLL requires a power-on self-calibration which happens when the + * PLL comes out of reset. The calibration is performed at an output frequency + * of ~1300 MHz which means that SW will have to vote on a voltage that's + * equal to or greater than SVS_L1 on the corresponding rail. Since this is not + * feasable to do in the atomic enable path, temporarily bring up the PLL here, + * let it calibrate, and place it in standby before returning. + */ +static int alpha_pll_lucid_prepare(struct clk_hw *hw) +{ + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + struct clk_hw *p; + u32 regval; + unsigned long prate; + int ret; + + /* Return early if calibration is not needed. */ + ret = regmap_read(pll->clkr.regmap, pll->offset + LUCID_PLL_OFF_STATUS, + ®val); + if (regval & LUCID_PCAL_DONE) + return ret; + + p = clk_hw_get_parent(hw); + if (!p) + return -EINVAL; + + prate = clk_hw_get_rate(p); + ret = clk_vote_rate_vdd(hw->core, LUCID_PLL_CAL_VAL * prate); + if (ret) + return ret; + + ret = alpha_pll_lucid_enable(hw); + if (ret) + goto ret_path; + + alpha_pll_lucid_disable(hw); +ret_path: + clk_unvote_rate_vdd(hw->core, LUCID_PLL_CAL_VAL * prate); + return 0; +} + +static unsigned long +alpha_pll_lucid_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + u32 l, frac; + + regmap_read(pll->clkr.regmap, pll->offset + LUCID_PLL_OFF_L_VAL, &l); + regmap_read(pll->clkr.regmap, pll->offset + LUCID_PLL_OFF_ALPHA_VAL, + &frac); + + return alpha_pll_calc_rate(pll, parent_rate, l, frac); +} + +static int alpha_pll_lucid_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long prate) +{ + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + unsigned long rrate; + u32 regval, l; + u64 a; + int ret; + + rrate = alpha_pll_round_rate(pll, rate, prate, &l, &a); + + /* + * Due to a limited number of bits for fractional rate programming, the + * rounded up rate could be marginally higher than the requested rate. + */ + if (rrate > (rate + LUCID_PLL_RATE_MARGIN) || rrate < rate) { + pr_err("Call set rate on the PLL with rounded rates!\n"); + return -EINVAL; + } + + regmap_write(pll->clkr.regmap, pll->offset + LUCID_PLL_OFF_L_VAL, l); + regmap_write(pll->clkr.regmap, pll->offset + LUCID_PLL_OFF_ALPHA_VAL, + a); + + /* Latch the PLL input */ + ret = regmap_update_bits(pll->clkr.regmap, pll->offset + PLL_MODE, + LUCID_PLL_UPDATE, LUCID_PLL_UPDATE); + if (ret) + return ret; + + /* Wait for 2 reference cycles before checking the ACK bit. */ + udelay(1); + regmap_read(pll->clkr.regmap, pll->offset + PLL_MODE, ®val); + if (!(regval & LUCID_PLL_ACK_LATCH)) { + WARN(1, "PLL latch failed. Output may be unstable!\n"); + return -EINVAL; + } + + /* Return the latch input to 0 */ + ret = regmap_update_bits(pll->clkr.regmap, pll->offset + PLL_MODE, + LUCID_PLL_UPDATE, 0); + if (ret) + return ret; + + if (clk_hw_is_enabled(hw)) { + ret = wait_for_pll_enable_lock(pll); + if (ret) + return ret; + } + + /* Wait for PLL output to stabilize */ + udelay(100); + return 0; +} + +static int alpha_pll_lucid_is_enabled(struct clk_hw *hw) +{ + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + + return lucid_pll_is_enabled(pll, pll->clkr.regmap); +} + +const struct clk_ops clk_alpha_pll_lucid_ops = { + .prepare = alpha_pll_lucid_prepare, + .enable = alpha_pll_lucid_enable, + .disable = alpha_pll_lucid_disable, + .is_enabled = alpha_pll_lucid_is_enabled, + .recalc_rate = alpha_pll_lucid_recalc_rate, + .round_rate = clk_alpha_pll_round_rate, + .set_rate = alpha_pll_lucid_set_rate, + .list_registers = clk_alpha_pll_list_registers, +}; +EXPORT_SYMBOL(clk_alpha_pll_lucid_ops); + +const struct clk_ops clk_alpha_pll_fixed_lucid_ops = { + .enable = alpha_pll_lucid_enable, + .disable = alpha_pll_lucid_disable, + .is_enabled = alpha_pll_lucid_is_enabled, + .recalc_rate = alpha_pll_lucid_recalc_rate, + .round_rate = clk_alpha_pll_round_rate, +}; +EXPORT_SYMBOL(clk_alpha_pll_fixed_lucid_ops); + +const struct clk_ops clk_alpha_pll_postdiv_lucid_ops = { + .recalc_rate = clk_alpha_pll_postdiv_recalc_rate, + .round_rate = clk_alpha_pll_postdiv_round_rate, + .set_rate = clk_alpha_pll_postdiv_set_rate, +}; +EXPORT_SYMBOL(clk_alpha_pll_postdiv_lucid_ops); diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h index 5157742c173682750e4c25ae10cdb0e3e13c2143..772120d291988a7243312522e05c8324bd07799d 100644 --- a/drivers/clk/qcom/clk-alpha-pll.h +++ b/drivers/clk/qcom/clk-alpha-pll.h @@ -34,6 +34,7 @@ enum pll_type { REGERA_PLL, FABIA_PLL, AGERA_PLL, + LUCID_PLL, }; /** @@ -143,6 +144,9 @@ extern const struct clk_ops clk_fabia_pll_ops; extern const struct clk_ops clk_fabia_fixed_pll_ops; extern const struct clk_ops clk_generic_pll_postdiv_ops; extern const struct clk_ops clk_agera_pll_ops; +extern const struct clk_ops clk_alpha_pll_lucid_ops; +extern const struct clk_ops clk_alpha_pll_fixed_lucid_ops; +extern const struct clk_ops clk_alpha_pll_postdiv_lucid_ops; void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, const struct alpha_pll_config *config); @@ -154,5 +158,6 @@ void clk_fabia_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, const struct alpha_pll_config *config); void clk_agera_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, const struct alpha_pll_config *config); - +int clk_lucid_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, + const struct alpha_pll_config *config); #endif diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c index 475ef6b0c12ea03174c6febf712ed81bb784d3d3..874a6f07b96e95c519278d1d43895301025534d6 100644 --- a/drivers/clk/qcom/clk-cpu-osm.c +++ b/drivers/clk/qcom/clk-cpu-osm.c @@ -305,6 +305,7 @@ static struct clk_osm l3_clk = { static DEFINE_CLK_VOTER(l3_cluster0_vote_clk, l3_clk, 0); static DEFINE_CLK_VOTER(l3_cluster1_vote_clk, l3_clk, 0); +static DEFINE_CLK_VOTER(l3_cluster2_vote_clk, l3_clk, 0); static DEFINE_CLK_VOTER(l3_misc_vote_clk, l3_clk, 0); static DEFINE_CLK_VOTER(l3_gpu_vote_clk, l3_clk, 0); @@ -458,6 +459,7 @@ static struct clk_osm cpu7_perfpcl_clk = { static struct clk_hw *osm_qcom_clk_hws[] = { [L3_CLUSTER0_VOTE_CLK] = &l3_cluster0_vote_clk.hw, [L3_CLUSTER1_VOTE_CLK] = &l3_cluster1_vote_clk.hw, + [L3_CLUSTER2_VOTE_CLK] = &l3_cluster2_vote_clk.hw, [L3_MISC_VOTE_CLK] = &l3_misc_vote_clk.hw, [L3_GPU_VOTE_CLK] = &l3_gpu_vote_clk.hw, [L3_CLK] = &l3_clk.hw, @@ -1037,6 +1039,7 @@ static void clk_cpu_osm_driver_sm6150_fixup(void) osm_qcom_clk_hws[CPU5_PERFCL_CLK] = NULL; osm_qcom_clk_hws[CPU7_PERFPCL_CLK] = NULL; osm_qcom_clk_hws[PERFPCL_CLK] = NULL; + osm_qcom_clk_hws[L3_CLUSTER2_VOTE_CLK] = NULL; osm_qcom_clk_hws[CPU4_PWRCL_CLK] = &cpu4_pwrcl_clk.hw; osm_qcom_clk_hws[CPU5_PWRCL_CLK] = &cpu5_pwrcl_clk.hw; osm_qcom_clk_hws[CPU7_PERFCL_CLK] = &cpu7_perfcl_clk.hw; @@ -1053,6 +1056,7 @@ static void clk_cpu_osm_driver_sdmshrike_fixup(void) { osm_qcom_clk_hws[CPU7_PERFPCL_CLK] = NULL; osm_qcom_clk_hws[PERFPCL_CLK] = NULL; + osm_qcom_clk_hws[L3_CLUSTER2_VOTE_CLK] = NULL; osm_qcom_clk_hws[CPU7_PERFCL_CLK] = &cpu7_perfcl_clk.hw; clk_cpu_map[7] = &cpu7_perfcl_clk; @@ -1173,6 +1177,8 @@ static int clk_cpu_osm_driver_probe(struct platform_device *pdev) "clk: Failed to enable cluster0 clock for L3\n"); WARN(clk_prepare_enable(l3_cluster1_vote_clk.hw.clk), "clk: Failed to enable cluster1 clock for L3\n"); + WARN(clk_prepare_enable(l3_cluster2_vote_clk.hw.clk), + "clk: Failed to enable cluster2 clock for L3\n"); WARN(clk_prepare_enable(l3_misc_vote_clk.hw.clk), "clk: Failed to enable misc clock for L3\n"); WARN(clk_prepare_enable(l3_gpu_vote_clk.hw.clk), diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c index bf1271373d768c894542ad3978ae3b30866ea2ee..f8e89d4c47195d1d3f8ffffbc7d07c8d6d1d8f2c 100644 --- a/drivers/clk/qcom/clk-rpmh.c +++ b/drivers/clk/qcom/clk-rpmh.c @@ -372,6 +372,7 @@ static const struct of_device_id clk_rpmh_match_table[] = { { .compatible = "qcom,rpmh-clk-sdmshrike", .data = &clk_rpmh_sdmshrike}, { .compatible = "qcom,rpmh-clk-sm6150", .data = &clk_rpmh_sm6150}, { .compatible = "qcom,rpmh-clk-sdmmagpie", .data = &clk_rpmh_sm6150}, + { .compatible = "qcom,rpmh-clk-sdxprairie", .data = &clk_rpmh_sm8150}, { } }; MODULE_DEVICE_TABLE(of, clk_rpmh_match_table); diff --git a/drivers/clk/qcom/debugcc-sdmmagpie.c b/drivers/clk/qcom/debugcc-sdmmagpie.c index 3efe77f77c73d6bd7dcdaf647e927189f6fe0327..7f9c9701138e6cc3d8212261e1fdd3f6757dd196 100644 --- a/drivers/clk/qcom/debugcc-sdmmagpie.c +++ b/drivers/clk/qcom/debugcc-sdmmagpie.c @@ -273,6 +273,7 @@ static struct clk_debug_mux gcc_debug_mux = { .src_sel_shift = 0, .post_div_mask = 0xF, .post_div_shift = 0, + .period_offset = 0x50, MUX_SRC_LIST( { "cam_cc_bps_ahb_clk", 0x46, 4, CAM_CC, 0xE, 0xFF, 0, 0xF, 0, 4, 0xD000, 0xD004, 0xD008 }, diff --git a/drivers/clk/qcom/debugcc-sdxprairie.c b/drivers/clk/qcom/debugcc-sdxprairie.c new file mode 100644 index 0000000000000000000000000000000000000000..bcf993264bdf0a9a6e112797d8338fd4be73f90a --- /dev/null +++ b/drivers/clk/qcom/debugcc-sdxprairie.c @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk-debug.h" + +static struct measure_clk_data debug_mux_priv = { + .ctl_reg = 0x79004, + .status_reg = 0x79008, + .xo_div4_cbcr = 0x22010, +}; + +static const char *const debug_mux_parent_names[] = { + "gcc_ahb_pcie_link_clk", + "gcc_blsp1_ahb_clk", + "gcc_blsp1_qup1_i2c_apps_clk", + "gcc_blsp1_qup1_spi_apps_clk", + "gcc_blsp1_qup2_i2c_apps_clk", + "gcc_blsp1_qup2_spi_apps_clk", + "gcc_blsp1_qup3_i2c_apps_clk", + "gcc_blsp1_qup3_spi_apps_clk", + "gcc_blsp1_qup4_i2c_apps_clk", + "gcc_blsp1_qup4_spi_apps_clk", + "gcc_blsp1_sleep_clk", + "gcc_blsp1_uart1_apps_clk", + "gcc_blsp1_uart2_apps_clk", + "gcc_blsp1_uart3_apps_clk", + "gcc_blsp1_uart4_apps_clk", + "gcc_boot_rom_ahb_clk", + "gcc_ce1_ahb_clk", + "gcc_ce1_axi_clk", + "gcc_ce1_clk", + "gcc_cpuss_ahb_clk", + "gcc_cpuss_gnoc_clk", + "gcc_cpuss_rbcpr_clk", + "gcc_eth_axi_clk", + "gcc_eth_ptp_clk", + "gcc_eth_rgmii_clk", + "gcc_eth_slave_ahb_clk", + "gcc_gp1_clk", + "gcc_gp2_clk", + "gcc_gp3_clk", + "gcc_pcie_aux_clk", + "gcc_pcie_cfg_ahb_clk", + "gcc_pcie_mstr_axi_clk", + "gcc_pcie_pipe_clk", + "gcc_pcie_rchng_phy_clk", + "gcc_pcie_sleep_clk", + "gcc_pcie_slv_axi_clk", + "gcc_pcie_slv_q2a_axi_clk", + "gcc_pdm2_clk", + "gcc_pdm_ahb_clk", + "gcc_pdm_xo4_clk", + "gcc_sdcc1_ahb_clk", + "gcc_sdcc1_apps_clk", + "gcc_spmi_fetcher_ahb_clk", + "gcc_spmi_fetcher_clk", + "gcc_sys_noc_cpuss_ahb_clk", + "gcc_usb30_master_clk", + "gcc_usb30_mock_utmi_clk", + "gcc_usb30_mstr_axi_clk", + "gcc_usb30_sleep_clk", + "gcc_usb30_slv_ahb_clk", + "gcc_usb3_phy_aux_clk", + "gcc_usb3_phy_pipe_clk", + "gcc_usb_phy_cfg_ahb2phy_clk", + "gcc_xo_div4_clk", + "gcc_xo_pcie_link_clk", + "measure_only_bimc_clk", + "measure_only_ipa_2x_clk", + "measure_only_snoc_clk", +}; + +static struct clk_debug_mux gcc_debug_mux = { + .priv = &debug_mux_priv, + .debug_offset = 0x79000, + .post_div_offset = 0x29000, + .cbcr_offset = 0x29004, + .src_sel_mask = 0x3FF, + .src_sel_shift = 0, + .post_div_mask = 0xF, + .post_div_shift = 0, + MUX_SRC_LIST( + { "gcc_ahb_pcie_link_clk", 0xCF, 4, GCC, + 0xCF, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_blsp1_ahb_clk", 0x34, 4, GCC, + 0x34, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_blsp1_qup1_i2c_apps_clk", 0x37, 4, GCC, + 0x37, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_blsp1_qup1_spi_apps_clk", 0x36, 4, GCC, + 0x36, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_blsp1_qup2_i2c_apps_clk", 0x3B, 4, GCC, + 0x3B, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_blsp1_qup2_spi_apps_clk", 0x3A, 4, GCC, + 0x3A, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_blsp1_qup3_i2c_apps_clk", 0x3F, 4, GCC, + 0x3F, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_blsp1_qup3_spi_apps_clk", 0x3E, 4, GCC, + 0x3E, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_blsp1_qup4_i2c_apps_clk", 0x43, 4, GCC, + 0x43, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_blsp1_qup4_spi_apps_clk", 0x42, 4, GCC, + 0x42, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_blsp1_sleep_clk", 0x35, 4, GCC, + 0x35, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_blsp1_uart1_apps_clk", 0x38, 4, GCC, + 0x38, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_blsp1_uart2_apps_clk", 0x3C, 4, GCC, + 0x3C, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_blsp1_uart3_apps_clk", 0x40, 4, GCC, + 0x40, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_blsp1_uart4_apps_clk", 0x44, 4, GCC, + 0x44, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_boot_rom_ahb_clk", 0x4B, 4, GCC, + 0x4B, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_ce1_ahb_clk", 0x60, 4, GCC, + 0x60, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_ce1_axi_clk", 0x5F, 4, GCC, + 0x5F, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_ce1_clk", 0x5E, 4, GCC, + 0x5E, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_cpuss_ahb_clk", 0x74, 4, GCC, + 0x74, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_cpuss_gnoc_clk", 0x75, 4, GCC, + 0x75, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_cpuss_rbcpr_clk", 0x76, 4, GCC, + 0x76, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_eth_axi_clk", 0xCB, 4, GCC, + 0xCB, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_eth_ptp_clk", 0xFD, 4, GCC, + 0xFD, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_eth_rgmii_clk", 0xC9, 4, GCC, + 0xC9, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_eth_slave_ahb_clk", 0xCA, 4, GCC, + 0xCA, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_gp1_clk", 0x85, 4, GCC, + 0x85, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_gp2_clk", 0x86, 4, GCC, + 0x86, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_gp3_clk", 0x87, 4, GCC, + 0x87, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_pcie_aux_clk", 0x99, 4, GCC, + 0x99, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_pcie_cfg_ahb_clk", 0x98, 4, GCC, + 0x98, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_pcie_mstr_axi_clk", 0x97, 4, GCC, + 0x97, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_pcie_pipe_clk", 0x9A, 4, GCC, + 0x9A, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_pcie_rchng_phy_clk", 0xB9, 4, GCC, + 0xB9, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_pcie_sleep_clk", 0x9C, 4, GCC, + 0x9C, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_pcie_slv_axi_clk", 0x96, 4, GCC, + 0x96, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_pcie_slv_q2a_axi_clk", 0x95, 4, GCC, + 0x95, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_pdm2_clk", 0x48, 4, GCC, + 0x48, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_pdm_ahb_clk", 0x46, 4, GCC, + 0x46, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_pdm_xo4_clk", 0x47, 4, GCC, + 0x47, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_sdcc1_ahb_clk", 0x33, 4, GCC, + 0x33, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_sdcc1_apps_clk", 0x32, 4, GCC, + 0x32, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_spmi_fetcher_ahb_clk", 0xB5, 4, GCC, + 0xB5, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_spmi_fetcher_clk", 0xB4, 4, GCC, + 0xB4, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_sys_noc_cpuss_ahb_clk", 0x10B, 4, GCC, + 0x10B, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_usb30_master_clk", 0x28, 4, GCC, + 0x28, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_usb30_mock_utmi_clk", 0x2A, 4, GCC, + 0x2A, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_usb30_mstr_axi_clk", 0x4F, 4, GCC, + 0x4F, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_usb30_sleep_clk", 0x29, 4, GCC, + 0x29, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_usb30_slv_ahb_clk", 0x6B, 4, GCC, + 0x6B, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_usb3_phy_aux_clk", 0x2B, 4, GCC, + 0x2B, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_usb3_phy_pipe_clk", 0x2D, 4, GCC, + 0x2D, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_usb_phy_cfg_ahb2phy_clk", 0x31, 4, GCC, + 0x31, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_xo_div4_clk", 0x63, 4, GCC, + 0x63, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "gcc_xo_pcie_link_clk", 0x77, 4, GCC, + 0x77, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "measure_only_bimc_clk", 0x73, 4, GCC, + 0x73, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "measure_only_ipa_2x_clk", 0xAC, 4, GCC, + 0xAC, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + { "measure_only_snoc_clk", 0x109, 4, GCC, + 0x109, 0x3FF, 0, 0xF, 0, 4, 0x79000, 0x29000, 0x29004 }, + ), + .hw.init = &(struct clk_init_data){ + .name = "gcc_debug_mux", + .ops = &clk_debug_mux_ops, + .parent_names = debug_mux_parent_names, + .num_parents = ARRAY_SIZE(debug_mux_parent_names), + .flags = CLK_IS_MEASURE, + }, +}; + +static const struct of_device_id clk_debug_match_table[] = { + { .compatible = "qcom,debugcc-sdxprairie" }, + { } +}; + +static int map_debug_bases(struct platform_device *pdev, char *base, int cc) +{ + if (!of_get_property(pdev->dev.of_node, base, NULL)) + return -ENODEV; + + gcc_debug_mux.regmap[cc] = + syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + base); + if (IS_ERR(gcc_debug_mux.regmap[cc])) { + pr_err("Failed to map %s (ret=%ld)\n", base, + PTR_ERR(gcc_debug_mux.regmap[cc])); + return PTR_ERR(gcc_debug_mux.regmap[cc]); + } + return 0; +} + +static int clk_debug_sdxprairie_probe(struct platform_device *pdev) +{ + struct clk *clk; + int ret = 0; + + clk = devm_clk_get(&pdev->dev, "xo_clk_src"); + if (IS_ERR(clk)) { + if (PTR_ERR(clk) != -EPROBE_DEFER) + dev_err(&pdev->dev, "Unable to get xo clock\n"); + return PTR_ERR(clk); + } + + debug_mux_priv.cxo = clk; + + gcc_debug_mux.regmap = devm_kcalloc(&pdev->dev, MAX_NUM_CC, + sizeof(*gcc_debug_mux.regmap), GFP_KERNEL); + if (!gcc_debug_mux.regmap) + return -ENOMEM; + + ret = map_debug_bases(pdev, "qcom,gcc", GCC); + if (ret) + return ret; + + clk = devm_clk_register(&pdev->dev, &gcc_debug_mux.hw); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "Unable to register GCC debug mux\n"); + return PTR_ERR(clk); + } + + ret = clk_debug_measure_register(&gcc_debug_mux.hw); + if (ret) + dev_err(&pdev->dev, "Could not register Measure clock\n"); + + return ret; +} + +static struct platform_driver clk_debug_driver = { + .probe = clk_debug_sdxprairie_probe, + .driver = { + .name = "debugcc-sdxprairie", + .of_match_table = clk_debug_match_table, + .owner = THIS_MODULE, + }, +}; + +int __init clk_debug_sdxprairie_init(void) +{ + return platform_driver_register(&clk_debug_driver); +} +fs_initcall(clk_debug_sdxprairie_init); + +MODULE_DESCRIPTION("QTI DEBUG CC SDXPRAIRIE Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:debugcc-sdxprairie"); diff --git a/drivers/clk/qcom/dispcc-sdmmagpie.c b/drivers/clk/qcom/dispcc-sdmmagpie.c index 6f6cbe90eea4436ebad63e6eecd9a7977c8a343d..e46fcde503627cedcbe26d926128e903622ebc95 100644 --- a/drivers/clk/qcom/dispcc-sdmmagpie.c +++ b/drivers/clk/qcom/dispcc-sdmmagpie.c @@ -32,7 +32,7 @@ #include "clk-regmap-divider.h" #include "common.h" #include "reset.h" -#include "vdd-level.h" +#include "vdd-level-sdmmagpie.h" #define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } @@ -93,6 +93,11 @@ static const char * const disp_cc_parent_names_2[] = { "core_bi_pll_test_se", }; +static const char * const disp_cc_parent_names_ao[] = { + "bi_tcxo_ao", + "core_bi_pll_test_se", +}; + static const struct parent_map disp_cc_parent_map_3[] = { { P_BI_TCXO, 0 }, { P_DISP_CC_PLL0_OUT_MAIN, 1 }, @@ -104,7 +109,7 @@ static const struct parent_map disp_cc_parent_map_3[] = { static const char * const disp_cc_parent_names_3[] = { "bi_tcxo", "disp_cc_pll0", - "gpll0", + "gcc_disp_gpll0_clk_src", "disp_cc_pll0_out_even", "core_bi_pll_test_se", }; @@ -131,7 +136,7 @@ static const struct parent_map disp_cc_parent_map_5[] = { static const char * const disp_cc_parent_names_5[] = { "bi_tcxo", - "gpll0", + "gcc_disp_gpll0_clk_src", "core_bi_pll_test_se", }; @@ -195,6 +200,7 @@ static struct clk_rcg2 disp_cc_mdss_ahb_clk_src = { .name = "disp_cc_mdss_ahb_clk_src", .parent_names = disp_cc_parent_names_5, .num_parents = 3, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, .vdd_class = &vdd_cx, .num_rate_max = VDD_NUM, @@ -299,8 +305,8 @@ static struct clk_rcg2 disp_cc_mdss_dp_crypto_clk_src = { }; static const struct freq_tbl ftbl_disp_cc_mdss_dp_link_clk_src[] = { - F(162000, P_DP_PHY_PLL_LINK_CLK, 2, 0, 0), - F(270000, P_DP_PHY_PLL_LINK_CLK, 2, 0, 0), + F(162000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0), + F(270000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0), F(540000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0), F(810000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0), { } @@ -561,13 +567,9 @@ static struct clk_rcg2 disp_cc_xo_clk_src = { .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src, .clkr.hw.init = &(struct clk_init_data){ .name = "disp_cc_xo_clk_src", - .parent_names = disp_cc_parent_names_2, + .parent_names = disp_cc_parent_names_ao, .num_parents = 2, .ops = &clk_rcg2_ops, - .vdd_class = &vdd_cx, - .num_rate_max = VDD_NUM, - .rate_max = (unsigned long[VDD_NUM]) { - [VDD_LOWER] = 19200000}, }, }; @@ -636,7 +638,7 @@ static struct clk_branch disp_cc_mdss_byte0_intf_clk = { "disp_cc_mdss_byte0_div_clk_src", }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .flags = CLK_GET_RATE_NOCACHE, .ops = &clk_branch2_ops, }, }, diff --git a/drivers/clk/qcom/gcc-qcs405.c b/drivers/clk/qcom/gcc-qcs405.c index 3f6c4328a7e0b5c7383b9a88835cc79671817e53..c96da2882b2aef665ed4ad083fc634e2a26ea669 100644 --- a/drivers/clk/qcom/gcc-qcs405.c +++ b/drivers/clk/qcom/gcc-qcs405.c @@ -1044,12 +1044,12 @@ static struct clk_rcg2 hdmi_pclk_clk_src = { .mnd_width = 0, .hid_width = 5, .parent_map = gcc_parent_map_8, - .freq_tbl = ftbl_esc0_clk_src, .clkr.hw.init = &(struct clk_init_data){ .name = "hdmi_pclk_clk_src", .parent_names = gcc_parent_names_8, .num_parents = 3, - .ops = &clk_rcg2_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_byte2_ops, .vdd_class = &vdd_cx, .num_rate_max = VDD_NUM, .rate_max = (unsigned long[VDD_NUM]) { diff --git a/drivers/clk/qcom/gcc-sdmmagpie.c b/drivers/clk/qcom/gcc-sdmmagpie.c index f5c25883b1c2c901bc740b9fdd7aec2a4d3f4057..6309dd52837556583a629c25e9cabcffbe771167 100644 --- a/drivers/clk/qcom/gcc-sdmmagpie.c +++ b/drivers/clk/qcom/gcc-sdmmagpie.c @@ -31,7 +31,7 @@ #include "clk-branch.h" #include "clk-rcg.h" #include "clk-regmap.h" -#include "vdd-level.h" +#include "vdd-level-sdmmagpie.h" #define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } @@ -1504,7 +1504,7 @@ static struct clk_branch gcc_disp_gpll0_div_clk_src = { .hw.init = &(struct clk_init_data){ .name = "gcc_disp_gpll0_div_clk_src", .parent_names = (const char *[]){ - "gcc_gpll0_main_div_cdiv", + "gcc_pll0_main_div_cdiv", }, .num_parents = 1, .ops = &clk_branch2_ops, @@ -1646,7 +1646,7 @@ static struct clk_branch gcc_gpu_gpll0_div_clk_src = { .hw.init = &(struct clk_init_data){ .name = "gcc_gpu_gpll0_div_clk_src", .parent_names = (const char *[]){ - "gcc_gpll0_main_div_cdiv", + "gcc_pll0_main_div_cdiv", }, .num_parents = 1, .ops = &clk_branch2_ops, @@ -2674,6 +2674,7 @@ static struct clk_branch gcc_ufs_phy_phy_aux_hw_ctl_clk = { }; static struct clk_branch gcc_ufs_phy_rx_symbol_0_clk = { + .halt_reg = 0x7701c, .halt_check = BRANCH_HALT_SKIP, .clkr = { .enable_reg = 0x7701c, @@ -2686,6 +2687,7 @@ static struct clk_branch gcc_ufs_phy_rx_symbol_0_clk = { }; static struct clk_branch gcc_ufs_phy_tx_symbol_0_clk = { + .halt_reg = 0x77018, .halt_check = BRANCH_HALT_SKIP, .clkr = { .enable_reg = 0x77018, diff --git a/drivers/clk/qcom/gcc-sdxprairie.c b/drivers/clk/qcom/gcc-sdxprairie.c new file mode 100644 index 0000000000000000000000000000000000000000..bf3603272a8ee48990f19e66b92829ca88f93c74 --- /dev/null +++ b/drivers/clk/qcom/gcc-sdxprairie.c @@ -0,0 +1,1961 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + +#include +#include +#include +#include + +#include + +#include "common.h" +#include "clk-regmap.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-branch.h" +#include "reset.h" +#include "clk-alpha-pll.h" +#include "vdd-level.h" + +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } + +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_EVEN, + P_GPLL0_OUT_MAIN, + P_GPLL4_OUT_EVEN, + P_GPLL5_OUT_MAIN, + P_SLEEP_CLK, +}; + +static const struct parent_map gcc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL0_OUT_EVEN, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_0[] = { + "bi_tcxo", + "gpll0", + "gpll0_out_even", + "core_bi_pll_test_se", +}; +static const char * const gcc_parent_names_0_ao[] = { + "bi_tcxo_ao", + "gpll0", + "gpll0_out_even", + "core_bi_pll_test_se", +}; + +static const struct parent_map gcc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_1[] = { + "bi_tcxo", + "core_bi_pll_test_se", +}; + +static const struct parent_map gcc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL4_OUT_EVEN, 2 }, + { P_GPLL5_OUT_MAIN, 5 }, + { P_GPLL0_OUT_EVEN, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_2[] = { + "bi_tcxo", + "gpll0", + "gpll4_out_even", + "gpll5", + "gpll0_out_even", + "core_bi_pll_test_se", +}; + +static const struct parent_map gcc_parent_map_3[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_SLEEP_CLK, 5 }, + { P_GPLL0_OUT_EVEN, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_3[] = { + "bi_tcxo", + "gpll0", + "sleep_clk", + "gpll0_out_even", + "core_bi_pll_test_se", +}; + +static const struct parent_map gcc_parent_map_4[] = { + { P_BI_TCXO, 0 }, + { P_SLEEP_CLK, 5 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_4[] = { + "bi_tcxo", + "sleep_clk", + "core_bi_pll_test_se", +}; + +static const struct parent_map gcc_parent_map_5[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL4_OUT_EVEN, 2 }, + { P_GPLL0_OUT_EVEN, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_5[] = { + "bi_tcxo", + "gpll0", + "gpll4_out_even", + "gpll0_out_even", + "core_bi_pll_test_se", +}; + +static struct pll_vco lucid_vco[] = { + { 249600000, 2000000000, 0 }, +}; + +static struct clk_alpha_pll gpll0 = { + .offset = 0x0, + .vco_table = lucid_vco, + .num_vco = ARRAY_SIZE(lucid_vco), + .clkr = { + .enable_reg = 0x6d000, + .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_fixed_lucid_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 615000000, + [VDD_LOW] = 1066000000, + [VDD_LOW_L1] = 1600000000, + [VDD_NOMINAL] = 2000000000}, + }, + }, +}; + +static const struct clk_div_table post_div_table_lucid_even[] = { + { 0x0, 1 }, + { 0x1, 2 }, + { 0x3, 4 }, + { 0x7, 8 }, + { } +}; + +static struct clk_alpha_pll_postdiv gpll0_out_even = { + .offset = 0x0, + .post_div_shift = 8, + .post_div_table = post_div_table_lucid_even, + .num_post_div = ARRAY_SIZE(post_div_table_lucid_even), + .width = 4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpll0_out_even", + .parent_names = (const char *[]){ "gpll0" }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_lucid_ops, + }, +}; + +static struct clk_alpha_pll gpll4 = { + .offset = 0x76000, + .vco_table = lucid_vco, + .num_vco = ARRAY_SIZE(lucid_vco), + .clkr = { + .enable_reg = 0x6d000, + .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_fixed_lucid_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 615000000, + [VDD_LOW] = 1066000000, + [VDD_LOW_L1] = 1600000000, + [VDD_NOMINAL] = 2000000000}, + }, + }, +}; + +static struct clk_alpha_pll_postdiv gpll4_out_even = { + .offset = 0x76000, + .post_div_shift = 8, + .post_div_table = post_div_table_lucid_even, + .num_post_div = ARRAY_SIZE(post_div_table_lucid_even), + .width = 4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpll4_out_even", + .parent_names = (const char *[]){ "gpll4" }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_lucid_ops, + }, +}; + +static struct clk_alpha_pll gpll5 = { + .offset = 0x74000, + .vco_table = lucid_vco, + .num_vco = ARRAY_SIZE(lucid_vco), + .clkr = { + .enable_reg = 0x6d000, + .enable_mask = BIT(5), + .hw.init = &(struct clk_init_data){ + .name = "gpll5", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 615000000, + [VDD_LOW] = 1066000000, + [VDD_LOW_L1] = 1600000000, + [VDD_NOMINAL] = 2000000000}, + }, + }, +}; + +static const struct freq_tbl ftbl_gcc_blsp1_qup1_i2c_apps_clk_src[] = { + F(9600000, P_BI_TCXO, 2, 0, 0), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_blsp1_qup1_i2c_apps_clk_src = { + .cmd_rcgr = 0x11024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_qup1_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup1_i2c_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .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_MIN] = 9600000, + [VDD_LOWER] = 19200000, + [VDD_LOW] = 50000000}, + }, +}; + +static const struct freq_tbl ftbl_gcc_blsp1_qup1_spi_apps_clk_src[] = { + F(960000, P_BI_TCXO, 10, 1, 2), + F(4800000, P_BI_TCXO, 4, 0, 0), + F(9600000, P_BI_TCXO, 2, 0, 0), + F(15000000, P_GPLL0_OUT_EVEN, 5, 1, 4), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(24000000, P_GPLL0_OUT_MAIN, 12.5, 1, 2), + F(25000000, P_GPLL0_OUT_MAIN, 12, 1, 2), + F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_blsp1_qup1_spi_apps_clk_src = { + .cmd_rcgr = 0x1100c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_qup1_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup1_spi_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .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_MIN] = 9600000, + [VDD_LOWER] = 19200000, + [VDD_LOW] = 25000000, + [VDD_NOMINAL] = 50000000}, + }, +}; + +static struct clk_rcg2 gcc_blsp1_qup2_i2c_apps_clk_src = { + .cmd_rcgr = 0x13024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_qup1_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup2_i2c_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .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_MIN] = 9600000, + [VDD_LOWER] = 19200000, + [VDD_LOW] = 50000000}, + }, +}; + +static struct clk_rcg2 gcc_blsp1_qup2_spi_apps_clk_src = { + .cmd_rcgr = 0x1300c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_qup1_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup2_spi_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .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_MIN] = 9600000, + [VDD_LOWER] = 19200000, + [VDD_LOW] = 25000000, + [VDD_NOMINAL] = 50000000}, + }, +}; + +static struct clk_rcg2 gcc_blsp1_qup3_i2c_apps_clk_src = { + .cmd_rcgr = 0x15024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_qup1_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup3_i2c_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .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_MIN] = 9600000, + [VDD_LOWER] = 19200000, + [VDD_LOW] = 50000000}, + }, +}; + +static struct clk_rcg2 gcc_blsp1_qup3_spi_apps_clk_src = { + .cmd_rcgr = 0x1500c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_qup1_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup3_spi_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .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_MIN] = 9600000, + [VDD_LOWER] = 19200000, + [VDD_LOW] = 25000000, + [VDD_NOMINAL] = 50000000}, + }, +}; + +static struct clk_rcg2 gcc_blsp1_qup4_i2c_apps_clk_src = { + .cmd_rcgr = 0x17024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_qup1_i2c_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup4_i2c_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .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_MIN] = 9600000, + [VDD_LOWER] = 19200000, + [VDD_LOW] = 50000000}, + }, +}; + +static struct clk_rcg2 gcc_blsp1_qup4_spi_apps_clk_src = { + .cmd_rcgr = 0x1700c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_qup1_spi_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup4_spi_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .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_MIN] = 9600000, + [VDD_LOWER] = 19200000, + [VDD_LOW] = 25000000, + [VDD_NOMINAL] = 50000000}, + }, +}; + +static const struct freq_tbl ftbl_gcc_blsp1_uart1_apps_clk_src[] = { + F(3686400, P_GPLL0_OUT_EVEN, 1, 192, 15625), + F(7372800, P_GPLL0_OUT_EVEN, 1, 384, 15625), + F(9600000, P_BI_TCXO, 2, 0, 0), + F(14745600, P_GPLL0_OUT_EVEN, 1, 768, 15625), + F(16000000, P_GPLL0_OUT_EVEN, 1, 4, 75), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(19354839, P_GPLL0_OUT_MAIN, 15.5, 1, 2), + F(20000000, P_GPLL0_OUT_MAIN, 15, 1, 2), + F(20689655, P_GPLL0_OUT_MAIN, 14.5, 1, 2), + F(21428571, P_GPLL0_OUT_MAIN, 14, 1, 2), + F(22222222, P_GPLL0_OUT_MAIN, 13.5, 1, 2), + F(23076923, P_GPLL0_OUT_MAIN, 13, 1, 2), + F(24000000, P_GPLL0_OUT_MAIN, 5, 1, 5), + F(25000000, P_GPLL0_OUT_MAIN, 12, 1, 2), + F(26086957, P_GPLL0_OUT_MAIN, 11.5, 1, 2), + F(27272727, P_GPLL0_OUT_MAIN, 11, 1, 2), + F(28571429, P_GPLL0_OUT_MAIN, 10.5, 1, 2), + F(32000000, P_GPLL0_OUT_MAIN, 1, 4, 75), + F(40000000, P_GPLL0_OUT_MAIN, 15, 0, 0), + F(46400000, P_GPLL0_OUT_MAIN, 1, 29, 375), + F(48000000, P_GPLL0_OUT_MAIN, 12.5, 0, 0), + F(51200000, P_GPLL0_OUT_MAIN, 1, 32, 375), + F(56000000, P_GPLL0_OUT_MAIN, 1, 7, 75), + F(58982400, P_GPLL0_OUT_MAIN, 1, 1536, 15625), + F(60000000, P_GPLL0_OUT_MAIN, 10, 0, 0), + F(63157895, P_GPLL0_OUT_MAIN, 9.5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_blsp1_uart1_apps_clk_src = { + .cmd_rcgr = 0x1200c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_uart1_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart1_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .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_MIN] = 9600000, + [VDD_LOWER] = 19200000, + [VDD_LOW] = 48000000, + [VDD_NOMINAL] = 63157895}, + }, +}; + +static struct clk_rcg2 gcc_blsp1_uart2_apps_clk_src = { + .cmd_rcgr = 0x1400c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_uart1_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart2_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .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_MIN] = 9600000, + [VDD_LOWER] = 19200000, + [VDD_LOW] = 48000000, + [VDD_NOMINAL] = 63157895}, + }, +}; + +static struct clk_rcg2 gcc_blsp1_uart3_apps_clk_src = { + .cmd_rcgr = 0x1600c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_uart1_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart3_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .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_MIN] = 9600000, + [VDD_LOWER] = 19200000, + [VDD_LOW] = 48000000, + [VDD_NOMINAL] = 63157895}, + }, +}; + +static struct clk_rcg2 gcc_blsp1_uart4_apps_clk_src = { + .cmd_rcgr = 0x1800c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_blsp1_uart1_apps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart4_apps_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .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_MIN] = 9600000, + [VDD_LOWER] = 19200000, + [VDD_LOW] = 48000000, + [VDD_NOMINAL] = 63157895}, + }, +}; + +static const struct freq_tbl ftbl_gcc_cpuss_ahb_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_cpuss_ahb_clk_src = { + .cmd_rcgr = 0x24010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_cpuss_ahb_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_cpuss_ahb_clk_src", + .parent_names = gcc_parent_names_0_ao, + .num_parents = 4, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx_ao, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 19200000}, + }, +}; + +static const struct freq_tbl ftbl_gcc_cpuss_rbcpr_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_cpuss_rbcpr_clk_src = { + .cmd_rcgr = 0x2402c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_cpuss_rbcpr_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_cpuss_rbcpr_clk_src", + .parent_names = gcc_parent_names_0_ao, + .num_parents = 4, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx_ao, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 19200000}, + }, +}; + +static const struct freq_tbl ftbl_gcc_emac_clk_src[] = { + F(2500000, P_BI_TCXO, 1, 25, 192), + F(5000000, P_BI_TCXO, 1, 25, 96), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(250000000, P_GPLL4_OUT_EVEN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_emac_clk_src = { + .cmd_rcgr = 0x47020, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_5, + .freq_tbl = ftbl_gcc_emac_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_emac_clk_src", + .parent_names = gcc_parent_names_5, + .num_parents = 5, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 19200000, + [VDD_LOWER] = 50000000, + [VDD_LOW] = 250000000}, + }, +}; + +static const struct freq_tbl ftbl_gcc_emac_ptp_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(230400000, P_GPLL5_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_emac_ptp_clk_src = { + .cmd_rcgr = 0x47038, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_emac_ptp_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_emac_ptp_clk_src", + .parent_names = gcc_parent_names_2, + .num_parents = 6, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 19200000, + [VDD_LOWER] = 50000000, + [VDD_LOW] = 230400000}, + }, +}; + +static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_gp1_clk_src = { + .cmd_rcgr = 0x2b004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_gp1_clk_src", + .parent_names = gcc_parent_names_3, + .num_parents = 5, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 19200000, + [VDD_LOWER] = 50000000, + [VDD_LOW] = 100000000, + [VDD_NOMINAL] = 200000000}, + }, +}; + +static struct clk_rcg2 gcc_gp2_clk_src = { + .cmd_rcgr = 0x2c004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_gp2_clk_src", + .parent_names = gcc_parent_names_3, + .num_parents = 5, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 19200000, + [VDD_LOWER] = 50000000, + [VDD_LOW] = 100000000, + [VDD_NOMINAL] = 200000000}, + }, +}; + +static struct clk_rcg2 gcc_gp3_clk_src = { + .cmd_rcgr = 0x2d004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_gp3_clk_src", + .parent_names = gcc_parent_names_3, + .num_parents = 5, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 19200000, + [VDD_LOWER] = 50000000, + [VDD_LOW] = 100000000, + [VDD_NOMINAL] = 200000000}, + }, +}; + +static struct clk_rcg2 gcc_pcie_aux_phy_clk_src = { + .cmd_rcgr = 0x37034, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_cpuss_rbcpr_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_aux_phy_clk_src", + .parent_names = gcc_parent_names_4, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_mx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 19200000}, + }, +}; + +static const struct freq_tbl ftbl_gcc_pcie_rchng_phy_clk_src[] = { + F(100000000, P_GPLL0_OUT_EVEN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie_rchng_phy_clk_src = { + .cmd_rcgr = 0x37050, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_pcie_rchng_phy_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_rchng_phy_clk_src", + .parent_names = gcc_parent_names_3, + .num_parents = 5, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_mx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 100000000}, + }, +}; + +static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = { + F(9600000, P_BI_TCXO, 2, 0, 0), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(60000000, P_GPLL0_OUT_MAIN, 10, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pdm2_clk_src = { + .cmd_rcgr = 0x19010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_pdm2_clk_src, + .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_MIN] = 9600000, + [VDD_LOWER] = 19200000, + [VDD_LOW] = 60000000}, + }, +}; + +static struct clk_rcg2 gcc_sdcc1_apps_clk_src = { + .cmd_rcgr = 0xf00c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_gp1_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_apps_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_MIN] = 19200000, + [VDD_LOWER] = 50000000, + [VDD_LOW] = 100000000, + [VDD_NOMINAL] = 200000000}, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb30_master_clk_src[] = { + F(200000000, P_GPLL0_OUT_EVEN, 1.5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb30_master_clk_src = { + .cmd_rcgr = 0xb024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_master_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_master_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_mx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 200000000}, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb30_mock_utmi_clk_src[] = { + F(60000000, P_GPLL0_OUT_EVEN, 5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb30_mock_utmi_clk_src = { + .cmd_rcgr = 0xb03c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_mock_utmi_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_mock_utmi_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_mx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 60000000}, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb3_phy_aux_clk_src[] = { + F(1000000, P_BI_TCXO, 1, 5, 96), + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb3_phy_aux_clk_src = { + .cmd_rcgr = 0xb064, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_usb3_phy_aux_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_phy_aux_clk_src", + .parent_names = gcc_parent_names_4, + .num_parents = 3, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + .vdd_class = &vdd_mx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_MIN] = 19200000}, + }, +}; + +static struct clk_branch gcc_ahb_pcie_link_clk = { + .halt_reg = 0x22004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x22004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ahb_pcie_link_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_ahb_clk = { + .halt_reg = 0x10004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d008, + .enable_mask = BIT(14), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup1_i2c_apps_clk = { + .halt_reg = 0x11008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x11008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup1_i2c_apps_clk", + .parent_names = (const char *[]){ + "gcc_blsp1_qup1_i2c_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup1_spi_apps_clk = { + .halt_reg = 0x11004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x11004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup1_spi_apps_clk", + .parent_names = (const char *[]){ + "gcc_blsp1_qup1_spi_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup2_i2c_apps_clk = { + .halt_reg = 0x13008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup2_i2c_apps_clk", + .parent_names = (const char *[]){ + "gcc_blsp1_qup2_i2c_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup2_spi_apps_clk = { + .halt_reg = 0x13004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x13004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup2_spi_apps_clk", + .parent_names = (const char *[]){ + "gcc_blsp1_qup2_spi_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup3_i2c_apps_clk = { + .halt_reg = 0x15008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x15008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup3_i2c_apps_clk", + .parent_names = (const char *[]){ + "gcc_blsp1_qup3_i2c_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup3_spi_apps_clk = { + .halt_reg = 0x15004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x15004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup3_spi_apps_clk", + .parent_names = (const char *[]){ + "gcc_blsp1_qup3_spi_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup4_i2c_apps_clk = { + .halt_reg = 0x17008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup4_i2c_apps_clk", + .parent_names = (const char *[]){ + "gcc_blsp1_qup4_i2c_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_qup4_spi_apps_clk = { + .halt_reg = 0x17004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_qup4_spi_apps_clk", + .parent_names = (const char *[]){ + "gcc_blsp1_qup4_spi_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart1_apps_clk = { + .halt_reg = 0x12004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x12004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart1_apps_clk", + .parent_names = (const char *[]){ + "gcc_blsp1_uart1_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart2_apps_clk = { + .halt_reg = 0x14004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x14004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart2_apps_clk", + .parent_names = (const char *[]){ + "gcc_blsp1_uart2_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart3_apps_clk = { + .halt_reg = 0x16004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x16004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart3_apps_clk", + .parent_names = (const char *[]){ + "gcc_blsp1_uart3_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_blsp1_uart4_apps_clk = { + .halt_reg = 0x18004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x18004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_blsp1_uart4_apps_clk", + .parent_names = (const char *[]){ + "gcc_blsp1_uart4_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_boot_rom_ahb_clk = { + .halt_reg = 0x1c004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x1c004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x6d008, + .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_ce1_ahb_clk = { + .halt_reg = 0x2100c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2100c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x6d008, + .enable_mask = BIT(3), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ce1_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ce1_axi_clk = { + .halt_reg = 0x21008, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d008, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ce1_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ce1_clk = { + .halt_reg = 0x21004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d008, + .enable_mask = BIT(5), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ce1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cpuss_ahb_clk = { + .halt_reg = 0x24000, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d008, + .enable_mask = BIT(21), + .hw.init = &(struct clk_init_data){ + .name = "gcc_cpuss_ahb_clk", + .parent_names = (const char *[]){ + "gcc_cpuss_ahb_clk_src", + }, + .num_parents = 1, + .flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cpuss_gnoc_clk = { + .halt_reg = 0x24004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x24004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x6d008, + .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_rbcpr_clk = { + .halt_reg = 0x24008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x24008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_cpuss_rbcpr_clk", + .parent_names = (const char *[]){ + "gcc_cpuss_rbcpr_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_eth_axi_clk = { + .halt_reg = 0x4701c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4701c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_eth_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_eth_ptp_clk = { + .halt_reg = 0x47018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x47018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_eth_ptp_clk", + .parent_names = (const char *[]){ + "gcc_emac_ptp_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_eth_rgmii_clk = { + .halt_reg = 0x47010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x47010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_eth_rgmii_clk", + .parent_names = (const char *[]){ + "gcc_emac_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_eth_slave_ahb_clk = { + .halt_reg = 0x47014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x47014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_eth_slave_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp1_clk = { + .halt_reg = 0x2b000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b000, + .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 = 0x2c000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2c000, + .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 = 0x2d000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2d000, + .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_pcie_0_clkref_clk = { + .halt_reg = 0x88004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x88004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_0_clkref_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_aux_clk = { + .halt_reg = 0x37024, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d010, + .enable_mask = BIT(3), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_aux_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_cfg_ahb_clk = { + .halt_reg = 0x3701c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d010, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_mstr_axi_clk = { + .halt_reg = 0x37018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d010, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_pipe_clk = { + .halt_reg = 0x3702c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d010, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_rchng_phy_clk = { + .halt_reg = 0x37020, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d010, + .enable_mask = BIT(7), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_rchng_phy_clk", + .parent_names = (const char *[]){ + "gcc_pcie_rchng_phy_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_sleep_clk = { + .halt_reg = 0x37028, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d010, + .enable_mask = BIT(6), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_sleep_clk", + .parent_names = (const char *[]){ + "gcc_pcie_aux_phy_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_slv_axi_clk = { + .halt_reg = 0x37014, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x37014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x6d010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_slv_q2a_axi_clk = { + .halt_reg = 0x37010, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d010, + .enable_mask = BIT(5), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm2_clk = { + .halt_reg = 0x1900c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1900c, + .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 = 0x19004, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0x19004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x19004, + .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 = 0x19008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x19008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_pdm_xo4_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_ahb_clk = { + .halt_reg = 0xf008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf008, + .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 = 0xf004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf004, + .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, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sys_noc_cpuss_ahb_clk = { + .halt_reg = 0x4010, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x6d008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sys_noc_cpuss_ahb_clk", + .parent_names = (const char *[]){ + "gcc_cpuss_ahb_clk_src", + }, + .num_parents = 1, + .flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_master_clk = { + .halt_reg = 0xb010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_master_clk", + .parent_names = (const char *[]){ + "gcc_usb30_master_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_mock_utmi_clk = { + .halt_reg = 0xb020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_mock_utmi_clk", + .parent_names = (const char *[]){ + "gcc_usb30_mock_utmi_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_mstr_axi_clk = { + .halt_reg = 0xb014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_sleep_clk = { + .halt_reg = 0xb01c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb01c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_slv_ahb_clk = { + .halt_reg = 0xb018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb018, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb30_slv_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_phy_aux_clk = { + .halt_reg = 0xb058, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb058, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_phy_aux_clk", + .parent_names = (const char *[]){ + "gcc_usb3_phy_aux_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_phy_pipe_clk = { + .halt_reg = 0xb05c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb05c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_phy_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_clkref_clk = { + .halt_reg = 0x88000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x88000, + .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_usb_phy_cfg_ahb2phy_clk = { + .halt_reg = 0xe004, + .halt_check = BRANCH_HALT, + .hwcg_reg = 0xe004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xe004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb_phy_cfg_ahb2phy_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_xo_pcie_link_clk = { + .halt_reg = 0x22008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x22008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_xo_pcie_link_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +/* Measure-only clock for ddrss_gcc_debug_clk. */ +static struct clk_dummy measure_only_bimc_clk = { + .rrate = 1000, + .hw.init = &(struct clk_init_data){ + .name = "measure_only_bimc_clk", + .ops = &clk_dummy_ops, + }, +}; + +/* Measure-only clock for gcc_ipa_2x_clk. */ +static struct clk_dummy measure_only_ipa_2x_clk = { + .rrate = 1000, + .hw.init = &(struct clk_init_data){ + .name = "measure_only_ipa_2x_clk", + .ops = &clk_dummy_ops, + }, +}; + +/* Measure-only clock for gcc_sys_noc_axi_clk. */ +static struct clk_dummy measure_only_snoc_clk = { + .rrate = 1000, + .hw.init = &(struct clk_init_data){ + .name = "measure_only_snoc_clk", + .ops = &clk_dummy_ops, + }, +}; + +struct clk_hw *gcc_sdxprairie_hws[] = { + [MEASURE_ONLY_BIMC_CLK] = &measure_only_bimc_clk.hw, + [MEASURE_ONLY_IPA_2X_CLK] = &measure_only_ipa_2x_clk.hw, + [MEASURE_ONLY_SNOC_CLK] = &measure_only_snoc_clk.hw, +}; + +static struct clk_regmap *gcc_sdxprairie_clocks[] = { + [GCC_AHB_PCIE_LINK_CLK] = &gcc_ahb_pcie_link_clk.clkr, + [GCC_BLSP1_AHB_CLK] = &gcc_blsp1_ahb_clk.clkr, + [GCC_BLSP1_QUP1_I2C_APPS_CLK] = &gcc_blsp1_qup1_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP1_I2C_APPS_CLK_SRC] = + &gcc_blsp1_qup1_i2c_apps_clk_src.clkr, + [GCC_BLSP1_QUP1_SPI_APPS_CLK] = &gcc_blsp1_qup1_spi_apps_clk.clkr, + [GCC_BLSP1_QUP1_SPI_APPS_CLK_SRC] = + &gcc_blsp1_qup1_spi_apps_clk_src.clkr, + [GCC_BLSP1_QUP2_I2C_APPS_CLK] = &gcc_blsp1_qup2_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP2_I2C_APPS_CLK_SRC] = + &gcc_blsp1_qup2_i2c_apps_clk_src.clkr, + [GCC_BLSP1_QUP2_SPI_APPS_CLK] = &gcc_blsp1_qup2_spi_apps_clk.clkr, + [GCC_BLSP1_QUP2_SPI_APPS_CLK_SRC] = + &gcc_blsp1_qup2_spi_apps_clk_src.clkr, + [GCC_BLSP1_QUP3_I2C_APPS_CLK] = &gcc_blsp1_qup3_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP3_I2C_APPS_CLK_SRC] = + &gcc_blsp1_qup3_i2c_apps_clk_src.clkr, + [GCC_BLSP1_QUP3_SPI_APPS_CLK] = &gcc_blsp1_qup3_spi_apps_clk.clkr, + [GCC_BLSP1_QUP3_SPI_APPS_CLK_SRC] = + &gcc_blsp1_qup3_spi_apps_clk_src.clkr, + [GCC_BLSP1_QUP4_I2C_APPS_CLK] = &gcc_blsp1_qup4_i2c_apps_clk.clkr, + [GCC_BLSP1_QUP4_I2C_APPS_CLK_SRC] = + &gcc_blsp1_qup4_i2c_apps_clk_src.clkr, + [GCC_BLSP1_QUP4_SPI_APPS_CLK] = &gcc_blsp1_qup4_spi_apps_clk.clkr, + [GCC_BLSP1_QUP4_SPI_APPS_CLK_SRC] = + &gcc_blsp1_qup4_spi_apps_clk_src.clkr, + [GCC_BLSP1_UART1_APPS_CLK] = &gcc_blsp1_uart1_apps_clk.clkr, + [GCC_BLSP1_UART1_APPS_CLK_SRC] = &gcc_blsp1_uart1_apps_clk_src.clkr, + [GCC_BLSP1_UART2_APPS_CLK] = &gcc_blsp1_uart2_apps_clk.clkr, + [GCC_BLSP1_UART2_APPS_CLK_SRC] = &gcc_blsp1_uart2_apps_clk_src.clkr, + [GCC_BLSP1_UART3_APPS_CLK] = &gcc_blsp1_uart3_apps_clk.clkr, + [GCC_BLSP1_UART3_APPS_CLK_SRC] = &gcc_blsp1_uart3_apps_clk_src.clkr, + [GCC_BLSP1_UART4_APPS_CLK] = &gcc_blsp1_uart4_apps_clk.clkr, + [GCC_BLSP1_UART4_APPS_CLK_SRC] = &gcc_blsp1_uart4_apps_clk_src.clkr, + [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr, + [GCC_CE1_AHB_CLK] = &gcc_ce1_ahb_clk.clkr, + [GCC_CE1_AXI_CLK] = &gcc_ce1_axi_clk.clkr, + [GCC_CE1_CLK] = &gcc_ce1_clk.clkr, + [GCC_CPUSS_AHB_CLK] = &gcc_cpuss_ahb_clk.clkr, + [GCC_CPUSS_AHB_CLK_SRC] = &gcc_cpuss_ahb_clk_src.clkr, + [GCC_CPUSS_GNOC_CLK] = &gcc_cpuss_gnoc_clk.clkr, + [GCC_CPUSS_RBCPR_CLK] = &gcc_cpuss_rbcpr_clk.clkr, + [GCC_CPUSS_RBCPR_CLK_SRC] = &gcc_cpuss_rbcpr_clk_src.clkr, + [GCC_EMAC_CLK_SRC] = &gcc_emac_clk_src.clkr, + [GCC_EMAC_PTP_CLK_SRC] = &gcc_emac_ptp_clk_src.clkr, + [GCC_ETH_AXI_CLK] = &gcc_eth_axi_clk.clkr, + [GCC_ETH_PTP_CLK] = &gcc_eth_ptp_clk.clkr, + [GCC_ETH_RGMII_CLK] = &gcc_eth_rgmii_clk.clkr, + [GCC_ETH_SLAVE_AHB_CLK] = &gcc_eth_slave_ahb_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_PCIE_0_CLKREF_CLK] = &gcc_pcie_0_clkref_clk.clkr, + [GCC_PCIE_AUX_CLK] = &gcc_pcie_aux_clk.clkr, + [GCC_PCIE_AUX_PHY_CLK_SRC] = &gcc_pcie_aux_phy_clk_src.clkr, + [GCC_PCIE_CFG_AHB_CLK] = &gcc_pcie_cfg_ahb_clk.clkr, + [GCC_PCIE_MSTR_AXI_CLK] = &gcc_pcie_mstr_axi_clk.clkr, + [GCC_PCIE_PIPE_CLK] = &gcc_pcie_pipe_clk.clkr, + [GCC_PCIE_RCHNG_PHY_CLK] = &gcc_pcie_rchng_phy_clk.clkr, + [GCC_PCIE_RCHNG_PHY_CLK_SRC] = &gcc_pcie_rchng_phy_clk_src.clkr, + [GCC_PCIE_SLEEP_CLK] = &gcc_pcie_sleep_clk.clkr, + [GCC_PCIE_SLV_AXI_CLK] = &gcc_pcie_slv_axi_clk.clkr, + [GCC_PCIE_SLV_Q2A_AXI_CLK] = &gcc_pcie_slv_q2a_axi_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_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_SYS_NOC_CPUSS_AHB_CLK] = &gcc_sys_noc_cpuss_ahb_clk.clkr, + [GCC_USB30_MASTER_CLK] = &gcc_usb30_master_clk.clkr, + [GCC_USB30_MASTER_CLK_SRC] = &gcc_usb30_master_clk_src.clkr, + [GCC_USB30_MOCK_UTMI_CLK] = &gcc_usb30_mock_utmi_clk.clkr, + [GCC_USB30_MOCK_UTMI_CLK_SRC] = &gcc_usb30_mock_utmi_clk_src.clkr, + [GCC_USB30_MSTR_AXI_CLK] = &gcc_usb30_mstr_axi_clk.clkr, + [GCC_USB30_SLEEP_CLK] = &gcc_usb30_sleep_clk.clkr, + [GCC_USB30_SLV_AHB_CLK] = &gcc_usb30_slv_ahb_clk.clkr, + [GCC_USB3_PHY_AUX_CLK] = &gcc_usb3_phy_aux_clk.clkr, + [GCC_USB3_PHY_AUX_CLK_SRC] = &gcc_usb3_phy_aux_clk_src.clkr, + [GCC_USB3_PHY_PIPE_CLK] = &gcc_usb3_phy_pipe_clk.clkr, + [GCC_USB3_PRIM_CLKREF_CLK] = &gcc_usb3_prim_clkref_clk.clkr, + [GCC_USB_PHY_CFG_AHB2PHY_CLK] = &gcc_usb_phy_cfg_ahb2phy_clk.clkr, + [GCC_XO_PCIE_LINK_CLK] = &gcc_xo_pcie_link_clk.clkr, + [GPLL0] = &gpll0.clkr, + [GPLL0_OUT_EVEN] = &gpll0_out_even.clkr, + [GPLL4] = &gpll4.clkr, + [GPLL4_OUT_EVEN] = &gpll4_out_even.clkr, + [GPLL5] = &gpll5.clkr, +}; + +static const struct qcom_reset_map gcc_sdxprairie_resets[] = { + [GCC_EMAC_BCR] = { 0x47000 }, + [GCC_PCIE_BCR] = { 0x37000 }, + [GCC_PCIE_LINK_DOWN_BCR] = { 0x77000 }, + [GCC_PCIE_PHY_BCR] = { 0x39000 }, + [GCC_PCIE_PHY_COM_BCR] = { 0x78004 }, + [GCC_QUSB2PHY_BCR] = { 0xd000 }, + [GCC_USB30_BCR] = { 0xb000 }, + [GCC_USB3_PHY_BCR] = { 0xc000 }, + [GCC_USB3PHY_PHY_BCR] = { 0xc004 }, + [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0xe000 }, +}; + +static const struct regmap_config gcc_sdxprairie_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x9b040, + .fast_io = true, +}; + +static const struct qcom_cc_desc gcc_sdxprairie_desc = { + .config = &gcc_sdxprairie_regmap_config, + .clks = gcc_sdxprairie_clocks, + .num_clks = ARRAY_SIZE(gcc_sdxprairie_clocks), + .hwclks = gcc_sdxprairie_hws, + .num_hwclks = ARRAY_SIZE(gcc_sdxprairie_hws), + .resets = gcc_sdxprairie_resets, + .num_resets = ARRAY_SIZE(gcc_sdxprairie_resets), +}; + +static const struct of_device_id gcc_sdxprairie_match_table[] = { + { .compatible = "qcom,gcc-sdxprairie" }, + { } +}; +MODULE_DEVICE_TABLE(of, gcc_sdxprairie_match_table); + +static int gcc_sdxprairie_probe(struct platform_device *pdev) +{ + struct clk *clk; + struct device *dev = &pdev->dev; + int ret = 0; + + clk = devm_clk_get(dev, "bi_tcxo"); + if (IS_ERR(clk)) { + if (PTR_ERR(clk) != -EPROBE_DEFER) + dev_err(dev, "Unable to get cxo clock\n"); + return PTR_ERR(clk); + } + + vdd_cx.regulator[0] = devm_regulator_get(dev, "vdd_cx"); + if (IS_ERR(vdd_cx.regulator[0])) { + if (!(PTR_ERR(vdd_cx.regulator[0]) == -EPROBE_DEFER)) + dev_err(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_probe(pdev, &gcc_sdxprairie_desc); + if (ret) + dev_err(&pdev->dev, "Failed to register GCC clocks\n"); + + return ret; +} + +static struct platform_driver gcc_sdxprairie_driver = { + .probe = gcc_sdxprairie_probe, + .driver = { + .name = "gcc-sdxprairie", + .of_match_table = gcc_sdxprairie_match_table, + }, +}; + +static int __init gcc_sdxprairie_init(void) +{ + return platform_driver_register(&gcc_sdxprairie_driver); +} +subsys_initcall(gcc_sdxprairie_init); + +static void __exit gcc_sdxprairie_exit(void) +{ + platform_driver_unregister(&gcc_sdxprairie_driver); +} +module_exit(gcc_sdxprairie_exit); + +MODULE_DESCRIPTION("QTI GCC SDXPRAIRIE Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:gcc-sdxprairie"); diff --git a/drivers/clk/qcom/gpucc-sdmmagpie.c b/drivers/clk/qcom/gpucc-sdmmagpie.c index 6bb05a19d13d0affa4d3bb8943768f5e84b6e5db..4f68ec35ca479e4a6564c6fc818cc61e7ddb1f39 100644 --- a/drivers/clk/qcom/gpucc-sdmmagpie.c +++ b/drivers/clk/qcom/gpucc-sdmmagpie.c @@ -33,7 +33,7 @@ #include "clk-regmap.h" #include "common.h" #include "reset.h" -#include "vdd-level.h" +#include "vdd-level-sdmmagpie.h" #define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } @@ -83,6 +83,7 @@ enum { P_GPU_CC_PLL1_OUT_EVEN, P_GPU_CC_PLL1_OUT_MAIN, P_GPU_CC_PLL1_OUT_ODD, + P_CRC_DIV, }; static const struct parent_map gpu_cc_parent_map_0[] = { @@ -123,6 +124,25 @@ static const char * const gpu_cc_parent_names_1[] = { "core_bi_pll_test_se", }; +static const struct parent_map gpu_cc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_CRC_DIV, 1 }, + { P_GPU_CC_PLL0_OUT_ODD, 2 }, + { P_GPU_CC_PLL1_OUT_EVEN, 3 }, + { P_GPU_CC_PLL1_OUT_ODD, 4 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gpu_cc_parent_names_2[] = { + "bi_tcxo", + "crc_div", + "gpu_cc_pll0_out_odd", + "gpu_cc_pll1_out_even", + "gpu_cc_pll1_out_odd", + "gcc_gpu_gpll0_clk_src", + "core_bi_pll_test_se", +}; static struct pll_vco fabia_vco[] = { { 249600000, 2000000000, 0 }, { 125000000, 1000000000, 1 }, @@ -183,6 +203,18 @@ static struct clk_alpha_pll_postdiv gpu_cc_pll0_out_even = { }, }; +static struct clk_fixed_factor crc_div = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "crc_div", + .parent_names = (const char *[]){ "gpu_cc_pll0_out_even" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + static struct clk_alpha_pll gpu_cc_pll1 = { .offset = 0x100, .vco_table = fabia_vco, @@ -244,16 +276,15 @@ static struct clk_rcg2 gpu_cc_gmu_clk_src = { }, }; -/* PLL would be 2 times. */ static const struct freq_tbl ftbl_gpu_cc_gx_gfx3d_clk_src[] = { - F(180000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), - F(267000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), - F(355000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), - F(430000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), - F(565000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), - F(650000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), - F(800000000, P_GPU_CC_PLL1_OUT_EVEN, 2, 0, 0), - F(825000000, P_GPU_CC_PLL1_OUT_EVEN, 2, 0, 0), + F(180000000, P_CRC_DIV, 1, 0, 0), + F(267000000, P_CRC_DIV, 1, 0, 0), + F(355000000, P_CRC_DIV, 1, 0, 0), + F(430000000, P_CRC_DIV, 1, 0, 0), + F(565000000, P_CRC_DIV, 1, 0, 0), + F(650000000, P_CRC_DIV, 1, 0, 0), + F(800000000, P_CRC_DIV, 1, 0, 0), + F(825000000, P_CRC_DIV, 1, 0, 0), { } }; @@ -261,12 +292,12 @@ static struct clk_rcg2 gpu_cc_gx_gfx3d_clk_src = { .cmd_rcgr = 0x101c, .mnd_width = 0, .hid_width = 5, - .parent_map = gpu_cc_parent_map_1, + .parent_map = gpu_cc_parent_map_2, .freq_tbl = ftbl_gpu_cc_gx_gfx3d_clk_src, .flags = FORCE_ENABLE_RCG, .clkr.hw.init = &(struct clk_init_data){ .name = "gpu_cc_gx_gfx3d_clk_src", - .parent_names = gpu_cc_parent_names_1, + .parent_names = gpu_cc_parent_names_2, .num_parents = 7, .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, @@ -312,7 +343,7 @@ static struct clk_branch gpu_cc_acd_cxo_clk = { static struct clk_branch gpu_cc_ahb_clk = { .halt_reg = 0x1078, - .halt_check = BRANCH_HALT, + .halt_check = BRANCH_HALT_DELAY, .clkr = { .enable_reg = 0x1078, .enable_mask = BIT(0), @@ -458,7 +489,7 @@ static struct clk_branch gpu_cc_gx_cxo_clk = { static struct clk_branch gpu_cc_gx_gfx3d_clk = { .halt_reg = 0x1054, - .halt_check = BRANCH_HALT, + .halt_check = BRANCH_HALT_SKIP, .clkr = { .enable_reg = 0x1054, .enable_mask = BIT(0), @@ -584,6 +615,13 @@ static int gpu_cc_sdmmagpie_probe(struct platform_device *pdev) /* Avoid turning on the rail during clock registration */ vdd_gx.skip_handoff = true; + /* Register clock fixed factor for CRC divide. */ + ret = devm_clk_hw_register(&pdev->dev, &crc_div.hw); + if (ret) { + dev_err(&pdev->dev, "Failed to register hardware clock\n"); + return ret; + } + regmap = qcom_cc_map(pdev, &gpu_cc_sdmmagpie_desc); if (IS_ERR(regmap)) { pr_err("Failed to map the gpu_cc registers\n"); diff --git a/drivers/clk/qcom/mdss/Makefile b/drivers/clk/qcom/mdss/Makefile index 36e8ef88e92dc45a641e444d49d86ed01de1d203..28a987330133b500e473a4aa941ef89de2e02ec3 100644 --- a/drivers/clk/qcom/mdss/Makefile +++ b/drivers/clk/qcom/mdss/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-dsi-pll-28nm-util.o obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-dsi-pll-14nm.o obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-dsi-pll-14nm-util.o obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-dp-pll-14nm.o +obj-$(CONFIG_QCOM_MDSS_PLL) += mdss-hdmi-pll-28lpm.o diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll-10nm.c b/drivers/clk/qcom/mdss/mdss-dp-pll-10nm.c index e30ef8251903b7ebf7e808e9baa81ac4635378a9..b0533b18a28b6009a139df2495af72ed1fa77219 100644 --- a/drivers/clk/qcom/mdss/mdss-dp-pll-10nm.c +++ b/drivers/clk/qcom/mdss/mdss-dp-pll-10nm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -108,12 +108,12 @@ static struct dp_pll_vco_clk dp_vco_clk = { }, }; -static struct clk_fixed_factor dp_link_clk_divsel_ten = { +static struct clk_fixed_factor dp_phy_pll_link_clk = { .div = 10, .mult = 1, .hw.init = &(struct clk_init_data){ - .name = "dp_link_clk_divsel_ten", + .name = "dp_phy_pll_link_clk", .parent_names = (const char *[]){ "dp_vco_clk" }, .num_parents = 1, @@ -207,14 +207,14 @@ static unsigned long mux_recalc_rate(struct clk_hw *hw, return (vco->rate / 2); } -static struct clk_regmap_mux dp_vco_divided_clk_src_mux = { +static struct clk_regmap_mux dp_phy_pll_vco_div_clk = { .reg = 0x64, .shift = 0, .width = 2, .clkr = { .hw.init = &(struct clk_init_data){ - .name = "dp_vco_divided_clk_src_mux", + .name = "dp_phy_pll_vco_div_clk", .parent_names = (const char *[]){"dp_vco_divsel_two_clk_src", "dp_vco_divsel_four_clk_src", @@ -228,11 +228,11 @@ static struct clk_regmap_mux dp_vco_divided_clk_src_mux = { static struct clk_hw *mdss_dp_pllcc_10nm[] = { [DP_VCO_CLK] = &dp_vco_clk.hw, - [DP_LINK_CLK_DIVSEL_TEN] = &dp_link_clk_divsel_ten.hw, + [DP_LINK_CLK_DIVSEL_TEN] = &dp_phy_pll_link_clk.hw, [DP_VCO_DIVIDED_TWO_CLK_SRC] = &dp_vco_divsel_two_clk_src.hw, [DP_VCO_DIVIDED_FOUR_CLK_SRC] = &dp_vco_divsel_four_clk_src.hw, [DP_VCO_DIVIDED_SIX_CLK_SRC] = &dp_vco_divsel_six_clk_src.hw, - [DP_VCO_DIVIDED_CLK_SRC_MUX] = &dp_vco_divided_clk_src_mux.clkr.hw, + [DP_VCO_DIVIDED_CLK_SRC_MUX] = &dp_phy_pll_vco_div_clk.clkr.hw, }; int dp_pll_clock_register_10nm(struct platform_device *pdev, @@ -274,7 +274,7 @@ int dp_pll_clock_register_10nm(struct platform_device *pdev, /* Set client data for vco, mux and div clocks */ regmap = devm_regmap_init(&pdev->dev, &dp_pixel_mux_regmap_ops, pll_res, &dp_pll_10nm_cfg); - dp_vco_divided_clk_src_mux.clkr.regmap = regmap; + dp_phy_pll_vco_div_clk.clkr.regmap = regmap; mux_clk_ops = clk_regmap_mux_closest_ops; mux_clk_ops.determine_rate = clk_mux_determine_rate; mux_clk_ops.recalc_rate = mux_recalc_rate; diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll-14nm.c b/drivers/clk/qcom/mdss/mdss-dp-pll-14nm.c index b6ca2b0e707d2e26dc76d59ddea3a470427e5109..20ccc80f124b5d28f59f293bb730c19617f6ebe6 100644 --- a/drivers/clk/qcom/mdss/mdss-dp-pll-14nm.c +++ b/drivers/clk/qcom/mdss/mdss-dp-pll-14nm.c @@ -101,7 +101,7 @@ static struct dp_pll_vco_clk dp_vco_clk = { }; static struct clk_fixed_factor dp_phy_pll_link_clk = { - .div = 5, + .div = 10, .mult = 1, .hw.init = &(struct clk_init_data){ @@ -292,6 +292,7 @@ static int dp_vco_pll_init_db_14nm(struct dp_pll_db *pdb, pdb->lock_cmp2_mode0 = 0x21; pdb->lock_cmp3_mode0 = 0x00; pdb->phy_vco_div = 0x1; + pdb->lane_mode_1 = 0xc6; break; case DP_VCO_HSCLK_RATE_2700MHZDIV1000: pdb->hsclk_sel = 0x24; @@ -303,6 +304,7 @@ static int dp_vco_pll_init_db_14nm(struct dp_pll_db *pdb, pdb->lock_cmp2_mode0 = 0x38; pdb->lock_cmp3_mode0 = 0x00; pdb->phy_vco_div = 0x1; + pdb->lane_mode_1 = 0xc4; break; case DP_VCO_HSCLK_RATE_5400MHZDIV1000: pdb->hsclk_sel = 0x20; @@ -314,6 +316,7 @@ static int dp_vco_pll_init_db_14nm(struct dp_pll_db *pdb, pdb->lock_cmp2_mode0 = 0x70; pdb->lock_cmp3_mode0 = 0x00; pdb->phy_vco_div = 0x2; + pdb->lane_mode_1 = 0xc4; break; default: return -EINVAL; @@ -334,17 +337,7 @@ int dp_config_vco_rate_14nm(struct dp_pll_vco_clk *vco, return res; } - if (pdb->lane_cnt != 4) { - if (pdb->orientation == ORIENTATION_CC2) - MDSS_PLL_REG_W(dp_res->phy_base, - DP_PHY_PD_CTL, 0x2d); - else - MDSS_PLL_REG_W(dp_res->phy_base, - DP_PHY_PD_CTL, 0x35); - } else { - MDSS_PLL_REG_W(dp_res->phy_base, - DP_PHY_PD_CTL, 0x3d); - } + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_PD_CTL, 0x3d); /* Make sure the PHY register writes are done */ wmb(); @@ -418,10 +411,15 @@ int dp_config_vco_rate_14nm(struct dp_pll_vco_clk *vco, QSERDES_COM_CORE_CLK_EN, 0x0f); wmb(); /* make sure write happens */ + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_LANE_MODE_1, pdb->lane_mode_1); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_LANE_MODE_1, pdb->lane_mode_1); + if (pdb->orientation == ORIENTATION_CC2) - MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_MODE, 0xc8); + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_MODE, 0xc9); else - MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_MODE, 0xd8); + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_MODE, 0xd9); wmb(); /* make sure write happens */ /* TX Lane configuration */ @@ -546,10 +544,8 @@ static bool dp_14nm_phy_rdy_status(struct mdss_pll_resources *dp_res) static int dp_pll_enable_14nm(struct clk_hw *hw) { int rc = 0; - u32 bias_en, drvr_en; struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); struct mdss_pll_resources *dp_res = vco->priv; - struct dp_pll_db *pdb = (struct dp_pll_db *)dp_res->priv; MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x01); MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x05); @@ -580,36 +576,14 @@ static int dp_pll_enable_14nm(struct clk_hw *hw) pr_debug("PLL is locked\n"); - if (pdb->lane_cnt == 1) { - bias_en = 0x3e; - drvr_en = 0x13; - } else { - bias_en = 0x3f; - drvr_en = 0x10; - } - - if (pdb->lane_cnt != 4) { - if (pdb->orientation == ORIENTATION_CC1) { - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX1_OFFSET + TXn_TRANSCEIVER_BIAS_EN, bias_en); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX1_OFFSET + TXn_HIGHZ_DRVR_EN, drvr_en); - } else { - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX0_OFFSET + TXn_TRANSCEIVER_BIAS_EN, bias_en); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX0_OFFSET + TXn_HIGHZ_DRVR_EN, drvr_en); - } - } else { - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX0_OFFSET + TXn_TRANSCEIVER_BIAS_EN, bias_en); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX0_OFFSET + TXn_HIGHZ_DRVR_EN, drvr_en); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX1_OFFSET + TXn_TRANSCEIVER_BIAS_EN, bias_en); - MDSS_PLL_REG_W(dp_res->phy_base, - QSERDES_TX1_OFFSET + TXn_HIGHZ_DRVR_EN, drvr_en); - } + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_TRANSCEIVER_BIAS_EN, 0x3f); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_HIGHZ_DRVR_EN, 0x10); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_TRANSCEIVER_BIAS_EN, 0x3f); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_HIGHZ_DRVR_EN, 0x10); MDSS_PLL_REG_W(dp_res->phy_base, QSERDES_TX0_OFFSET + TXn_TX_POL_INV, 0x0a); @@ -739,7 +713,7 @@ unsigned long dp_vco_recalc_rate_14nm(struct clk_hw *hw, { struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); int rc; - u32 div, hsclk_div, link2xclk_div = 0; + u32 div, hsclk_div; u64 vco_rate; struct mdss_pll_resources *dp_res = vco->priv; @@ -766,28 +740,12 @@ unsigned long dp_vco_recalc_rate_14nm(struct clk_hw *hw, hsclk_div = 5; } - div = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_MODE); - - if (div & 0xd8) - pr_err("DP PAR Rate not correct\n"); - - if ((div & 0x3) == 1) - link2xclk_div = 10; - else if ((div & 0x3) == 0) - link2xclk_div = 5; - else - pr_err("unsupported div. Phy_mode: %d\n", div); - - if (link2xclk_div == 10) { + if (hsclk_div == 5) + vco_rate = DP_VCO_HSCLK_RATE_1620MHZDIV1000; + else if (hsclk_div == 3) vco_rate = DP_VCO_HSCLK_RATE_2700MHZDIV1000; - } else { - if (hsclk_div == 5) - vco_rate = DP_VCO_HSCLK_RATE_1620MHZDIV1000; - else if (hsclk_div == 3) - vco_rate = DP_VCO_HSCLK_RATE_2700MHZDIV1000; - else - vco_rate = DP_VCO_HSCLK_RATE_5400MHZDIV1000; - } + else + vco_rate = DP_VCO_HSCLK_RATE_5400MHZDIV1000; pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate); diff --git a/drivers/clk/qcom/mdss/mdss-dp-pll-14nm.h b/drivers/clk/qcom/mdss/mdss-dp-pll-14nm.h index ccab78132cf0ce99855c1cdb1f151fd155ef9da4..566f694a267406b3585cc51a15e4eadcf302441d 100644 --- a/drivers/clk/qcom/mdss/mdss-dp-pll-14nm.h +++ b/drivers/clk/qcom/mdss/mdss-dp-pll-14nm.h @@ -176,6 +176,9 @@ struct dp_pll_db { /* PHY vco divider */ u32 phy_vco_div; + + /* TX settings */ + u32 lane_mode_1; }; int dp_vco_set_rate_14nm(struct clk_hw *hw, unsigned long rate, diff --git a/drivers/clk/qcom/mdss/mdss-hdmi-pll-28lpm.c b/drivers/clk/qcom/mdss/mdss-hdmi-pll-28lpm.c new file mode 100644 index 0000000000000000000000000000000000000000..c9fd4175444b1113ac7fcd0ea66da1abd9b0444b --- /dev/null +++ b/drivers/clk/qcom/mdss/mdss-hdmi-pll-28lpm.c @@ -0,0 +1,782 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include "mdss-pll.h" +#include "mdss-hdmi-pll.h" + +/* HDMI PLL macros */ +#define HDMI_PHY_PLL_REFCLK_CFG (0x0400) +#define HDMI_PHY_PLL_CHRG_PUMP_CFG (0x0404) +#define HDMI_PHY_PLL_LOOP_FLT_CFG0 (0x0408) +#define HDMI_PHY_PLL_LOOP_FLT_CFG1 (0x040c) +#define HDMI_PHY_PLL_IDAC_ADJ_CFG (0x0410) +#define HDMI_PHY_PLL_I_VI_KVCO_CFG (0x0414) +#define HDMI_PHY_PLL_PWRDN_B (0x0418) +#define HDMI_PHY_PLL_SDM_CFG0 (0x041c) +#define HDMI_PHY_PLL_SDM_CFG1 (0x0420) +#define HDMI_PHY_PLL_SDM_CFG2 (0x0424) +#define HDMI_PHY_PLL_SDM_CFG3 (0x0428) +#define HDMI_PHY_PLL_SDM_CFG4 (0x042c) +#define HDMI_PHY_PLL_SSC_CFG0 (0x0430) +#define HDMI_PHY_PLL_SSC_CFG1 (0x0434) +#define HDMI_PHY_PLL_SSC_CFG2 (0x0438) +#define HDMI_PHY_PLL_SSC_CFG3 (0x043c) +#define HDMI_PHY_PLL_LOCKDET_CFG0 (0x0440) +#define HDMI_PHY_PLL_LOCKDET_CFG1 (0x0444) +#define HDMI_PHY_PLL_LOCKDET_CFG2 (0x0448) +#define HDMI_PHY_PLL_VCOCAL_CFG0 (0x044c) +#define HDMI_PHY_PLL_VCOCAL_CFG1 (0x0450) +#define HDMI_PHY_PLL_VCOCAL_CFG2 (0x0454) +#define HDMI_PHY_PLL_VCOCAL_CFG3 (0x0458) +#define HDMI_PHY_PLL_VCOCAL_CFG4 (0x045c) +#define HDMI_PHY_PLL_VCOCAL_CFG5 (0x0460) +#define HDMI_PHY_PLL_VCOCAL_CFG6 (0x0464) +#define HDMI_PHY_PLL_VCOCAL_CFG7 (0x0468) +#define HDMI_PHY_PLL_DEBUG_SEL (0x046c) +#define HDMI_PHY_PLL_MISC0 (0x0470) +#define HDMI_PHY_PLL_MISC1 (0x0474) +#define HDMI_PHY_PLL_MISC2 (0x0478) +#define HDMI_PHY_PLL_MISC3 (0x047c) +#define HDMI_PHY_PLL_MISC4 (0x0480) +#define HDMI_PHY_PLL_MISC5 (0x0484) +#define HDMI_PHY_PLL_MISC6 (0x0488) +#define HDMI_PHY_PLL_DEBUG_BUS0 (0x048c) +#define HDMI_PHY_PLL_DEBUG_BUS1 (0x0490) +#define HDMI_PHY_PLL_DEBUG_BUS2 (0x0494) +#define HDMI_PHY_PLL_STATUS0 (0x0498) +#define HDMI_PHY_PLL_STATUS1 (0x049c) + +#define HDMI_PHY_REG_0 (0x0000) +#define HDMI_PHY_REG_1 (0x0004) +#define HDMI_PHY_REG_2 (0x0008) +#define HDMI_PHY_REG_3 (0x000c) +#define HDMI_PHY_REG_4 (0x0010) +#define HDMI_PHY_REG_5 (0x0014) +#define HDMI_PHY_REG_6 (0x0018) +#define HDMI_PHY_REG_7 (0x001c) +#define HDMI_PHY_REG_8 (0x0020) +#define HDMI_PHY_REG_9 (0x0024) +#define HDMI_PHY_REG_10 (0x0028) +#define HDMI_PHY_REG_11 (0x002c) +#define HDMI_PHY_REG_12 (0x0030) +#define HDMI_PHY_REG_BIST_CFG (0x0034) +#define HDMI_PHY_DEBUG_BUS_SEL (0x0038) +#define HDMI_PHY_REG_MISC0 (0x003c) +#define HDMI_PHY_REG_13 (0x0040) +#define HDMI_PHY_REG_14 (0x0044) +#define HDMI_PHY_REG_15 (0x0048) + +/* HDMI PHY/PLL bit field macros */ +#define SW_RESET BIT(2) +#define SW_RESET_PLL BIT(0) +#define PWRDN_B BIT(7) + +#define PLL_PWRDN_B BIT(3) +#define REG_VTEST_EN BIT(2) +#define PD_PLL BIT(1) +#define PD_PLL_REG BIT(0) + + +#define HDMI_PLL_POLL_DELAY_US 50 +#define HDMI_PLL_POLL_TIMEOUT_US 500 + +static int hdmi_pll_lock_status(struct mdss_pll_resources *hdmi_pll_res) +{ + u32 status; + int pll_locked = 0; + int rc; + + rc = mdss_pll_resource_enable(hdmi_pll_res, true); + if (rc) { + pr_err("pll resource can't be enabled\n"); + return rc; + } + + /* poll for PLL ready status */ + if (readl_poll_timeout_atomic( + (hdmi_pll_res->pll_base + HDMI_PHY_PLL_STATUS0), + status, ((status & BIT(0)) == 1), + HDMI_PLL_POLL_DELAY_US, + HDMI_PLL_POLL_TIMEOUT_US)) { + pr_debug("HDMI PLL status=%x failed to Lock\n", status); + pll_locked = 0; + } else { + pr_debug("HDMI PLL locked\n"); + pll_locked = 1; + } + mdss_pll_resource_enable(hdmi_pll_res, false); + + return pll_locked; +} + +static void hdmi_pll_disable_28lpm(struct clk_hw *hw) +{ + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk_hw(hw); + struct mdss_pll_resources *hdmi_pll_res = vco->priv; + u32 val; + + if (!hdmi_pll_res) { + pr_err("Invalid input parameter\n"); + return; + } + + val = MDSS_PLL_REG_R(hdmi_pll_res->pll_base, HDMI_PHY_REG_12); + val &= (~PWRDN_B); + MDSS_PLL_REG_W(hdmi_pll_res->pll_base, HDMI_PHY_REG_12, val); + + val = MDSS_PLL_REG_R(hdmi_pll_res->pll_base, HDMI_PHY_PLL_PWRDN_B); + val |= PD_PLL; + val &= (~PLL_PWRDN_B); + MDSS_PLL_REG_W(hdmi_pll_res->pll_base, HDMI_PHY_PLL_PWRDN_B, val); + + /* Make sure HDMI PHY/PLL are powered down */ + wmb(); + +} /* hdmi_pll_disable_28lpm */ + +static int hdmi_pll_enable_28lpm(struct clk_hw *hw) +{ + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk_hw(hw); + struct mdss_pll_resources *hdmi_pll_res = vco->priv; + void __iomem *pll_base; + u32 val; + int pll_lock_retry = 10; + + pll_base = hdmi_pll_res->pll_base; + + /* Assert PLL S/W reset */ + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_LOCKDET_CFG2, 0x8d); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_LOCKDET_CFG0, 0x10); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_LOCKDET_CFG1, 0x1a); + udelay(10); + /* De-assert PLL S/W reset */ + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_LOCKDET_CFG2, 0x0d); + + MDSS_PLL_REG_W(pll_base, HDMI_PHY_REG_1, 0xf2); + + udelay(10); + + MDSS_PLL_REG_W(pll_base, HDMI_PHY_REG_2, 0x1f); + + val = MDSS_PLL_REG_R(pll_base, HDMI_PHY_REG_12); + val |= BIT(5); + /* Assert PHY S/W reset */ + MDSS_PLL_REG_W(pll_base, HDMI_PHY_REG_12, val); + val &= ~BIT(5); + udelay(10); + /* De-assert PHY S/W reset */ + MDSS_PLL_REG_W(pll_base, HDMI_PHY_REG_12, val); + + val = MDSS_PLL_REG_R(pll_base, HDMI_PHY_REG_12); + val |= PWRDN_B; + MDSS_PLL_REG_W(pll_base, HDMI_PHY_REG_12, val); + + /* Wait 10 us for enabling global power for PHY */ + wmb(); + udelay(10); + + MDSS_PLL_REG_W(pll_base, HDMI_PHY_REG_3, 0x20); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_REG_4, 0x10); + + val = MDSS_PLL_REG_R(pll_base, HDMI_PHY_PLL_PWRDN_B); + val |= PLL_PWRDN_B; + val |= REG_VTEST_EN; + val &= ~PD_PLL; + val |= PD_PLL_REG; + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_PWRDN_B, val); + + MDSS_PLL_REG_W(pll_base, HDMI_PHY_REG_2, 0x81); + + do { + if (!hdmi_pll_lock_status(hdmi_pll_res)) { + /* PLL has still not locked. + * Do a software reset and try again + * Assert PLL S/W reset first + */ + MDSS_PLL_REG_W(pll_base, + HDMI_PHY_PLL_LOCKDET_CFG2, 0x8d); + + /* Wait for a short time before de-asserting + * to allow the hardware to complete its job. + * This much of delay should be fine for hardware + * to assert and de-assert. + */ + udelay(10); + MDSS_PLL_REG_W(pll_base, + HDMI_PHY_PLL_LOCKDET_CFG2, 0xd); + + /* Wait for a short duration for the PLL calibration + * before checking if the PLL gets locked + */ + udelay(350); + } else { + pr_debug("HDMI PLL locked\n"); + break; + } + + } while (--pll_lock_retry); + + if (!pll_lock_retry) { + pr_err("HDMI PLL not locked\n"); + hdmi_pll_disable_28lpm(hw); + return -EAGAIN; + } + + return 0; +} /* hdmi_pll_enable_28lpm */ + +static void hdmi_phy_pll_calculator_28lpm(unsigned long vco_rate, + struct mdss_pll_resources *hdmi_pll_res) +{ + u32 ref_clk = 19200000; + u32 integer_mode = 0; + u32 ref_clk_multiplier = integer_mode == 0 ? 2 : 1; + u32 int_ref_clk_freq = ref_clk * ref_clk_multiplier; + u32 refclk_cfg = 0; + u32 ten_power_six = 1000000; + u64 multiplier_q = 0; + u64 multiplier_r = 0; + u32 lf_cfg0 = 0; + u32 lf_cfg1 = 0; + u64 vco_cfg0 = 0; + u64 vco_cfg4 = 0; + u64 sdm_cfg0 = 0; + u64 sdm_cfg1 = 0; + u64 sdm_cfg2 = 0; + u32 val1 = 0; + u32 val2 = 0; + u32 val3 = 0; + void __iomem *pll_base = hdmi_pll_res->pll_base; + + multiplier_q = vco_rate; + multiplier_r = do_div(multiplier_q, int_ref_clk_freq); + + lf_cfg0 = multiplier_q > 30 ? 0 : (multiplier_q > 16 ? 16 : 32); + lf_cfg0 += integer_mode; + + lf_cfg1 = multiplier_q > 30 ? 0xc3 : (multiplier_q > 16 ? 0xbb : 0xf9); + + vco_cfg0 = vco_rate / ten_power_six; + vco_cfg4 = ((ref_clk * 5) / ten_power_six) - 1; + + sdm_cfg0 = (integer_mode * 64) + multiplier_q - 1; + sdm_cfg1 = 64 + multiplier_q - 1; + + sdm_cfg2 = (multiplier_r) * 65536; + do_div(sdm_cfg2, int_ref_clk_freq); + + pr_debug("lf_cfg0 = 0x%x lf_cfg1 = 0x%x\n", lf_cfg0, lf_cfg1); + pr_debug("vco_cfg0 = 0x%x vco_cfg4 = 0x%x\n", vco_cfg0, vco_cfg4); + pr_debug("sdm_cfg0 = 0x%x sdm_cfg1 = 0x%x sdm_cfg2 = 0x%x\n", + sdm_cfg0, sdm_cfg1, sdm_cfg2); + + refclk_cfg = MDSS_PLL_REG_R(pll_base, HDMI_PHY_PLL_REFCLK_CFG); + refclk_cfg &= ~0xf; + refclk_cfg |= (ref_clk_multiplier == 2) ? 0x8 + : (ref_clk_multiplier == 1) ? 0 : 0x2; + + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_REFCLK_CFG, refclk_cfg); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_CHRG_PUMP_CFG, 0x02); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_LOOP_FLT_CFG0, lf_cfg0); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_LOOP_FLT_CFG1, lf_cfg1); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_IDAC_ADJ_CFG, 0x2c); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_I_VI_KVCO_CFG, 0x06); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_PWRDN_B, 0x0a); + + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_SDM_CFG0, sdm_cfg0); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_SDM_CFG1, sdm_cfg1); + + val1 = sdm_cfg2 & 0xff; + val2 = (sdm_cfg2 >> 8) & 0xff; + val3 = (sdm_cfg2 >> 16) & 0xff; + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_SDM_CFG2, val1); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_SDM_CFG3, val2); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_SDM_CFG4, val3); + + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_SSC_CFG0, 0x9a); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_SSC_CFG1, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_SSC_CFG2, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_SSC_CFG3, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_LOCKDET_CFG0, 0x10); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_LOCKDET_CFG1, 0x1a); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_LOCKDET_CFG2, 0x0d); + + val1 = vco_cfg0 & 0xff; + val2 = (vco_cfg0 >> 8) & 0xff; + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_VCOCAL_CFG0, val1); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_VCOCAL_CFG1, val2); + + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_VCOCAL_CFG2, 0x3b); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_VCOCAL_CFG3, 0x00); + + val1 = vco_cfg4 & 0xff; + val2 = (vco_cfg4 >> 8) & 0xff; + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_VCOCAL_CFG4, val1); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_VCOCAL_CFG5, val2); + + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_VCOCAL_CFG6, 0x33); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_VCOCAL_CFG7, 0x03); + +} + +int hdmi_vco_set_rate_28lpm(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk_hw(hw); + struct mdss_pll_resources *hdmi_pll_res = vco->priv; + void __iomem *pll_base; + int rc; + + rc = mdss_pll_resource_enable(hdmi_pll_res, true); + if (rc) { + pr_err("pll resource can't be enabled\n"); + return rc; + } + + if (hdmi_pll_res->pll_on) + return 0; + + pll_base = hdmi_pll_res->pll_base; + + pr_debug("rate=%ld\n", rate); + + hdmi_phy_pll_calculator_28lpm(rate, hdmi_pll_res); + + /* Make sure writes complete before disabling iface clock */ + wmb(); + + vco->rate = rate; + hdmi_pll_res->vco_current_rate = rate; + + mdss_pll_resource_enable(hdmi_pll_res, false); + + + return 0; +} /* hdmi_pll_set_rate */ + +static unsigned long hdmi_vco_get_rate(struct hdmi_pll_vco_clk *vco) +{ + unsigned long freq = 0; + int rc = 0; + struct mdss_pll_resources *hdmi_pll_res = vco->priv; + + rc = mdss_pll_resource_enable(hdmi_pll_res, true); + if (rc) { + pr_err("Failed to enable hdmi pll resources\n"); + return 0; + } + + freq = MDSS_PLL_REG_R(hdmi_pll_res->pll_base, + HDMI_PHY_PLL_VCOCAL_CFG1) << 8 | + MDSS_PLL_REG_R(hdmi_pll_res->pll_base, + HDMI_PHY_PLL_VCOCAL_CFG0); + + switch (freq) { + case 742: + freq = 742500000; + break; + case 810: + if (MDSS_PLL_REG_R(hdmi_pll_res->pll_base, + HDMI_PHY_PLL_SDM_CFG3) == 0x18) + freq = 810000000; + else + freq = 810900000; + break; + case 1342: + freq = 1342500000; + break; + default: + freq *= 1000000; + } + mdss_pll_resource_enable(hdmi_pll_res, false); + + return freq; +} + +long hdmi_vco_round_rate_28lpm(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned long rrate = rate; + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk_hw(hw); + + if (rate < vco->min_rate) + rrate = vco->min_rate; + if (rate > vco->max_rate) + rrate = vco->max_rate; + + *parent_rate = rrate; + pr_debug("rrate=%ld\n", rrate); + + return rrate; +} + +int hdmi_vco_prepare_28lpm(struct clk_hw *hw) +{ + int rc = 0; + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk_hw(hw); + struct mdss_pll_resources *hdmi_res = vco->priv; + + pr_debug("rate=%ld\n", clk_hw_get_rate(hw)); + rc = mdss_pll_resource_enable(hdmi_res, true); + if (rc) { + pr_err("Failed to enable mdss HDMI pll resources\n"); + goto error; + } + + if ((hdmi_res->vco_cached_rate != 0) + && (hdmi_res->vco_cached_rate == clk_hw_get_rate(hw))) { + rc = vco->hw.init->ops->set_rate(hw, + hdmi_res->vco_cached_rate, hdmi_res->vco_cached_rate); + if (rc) { + pr_err("index=%d vco_set_rate failed. rc=%d\n", + rc, hdmi_res->index); + mdss_pll_resource_enable(hdmi_res, false); + goto error; + } + } + + rc = hdmi_pll_enable_28lpm(hw); + if (rc) { + mdss_pll_resource_enable(hdmi_res, false); + pr_err("ndx=%d failed to enable hdmi pll\n", + hdmi_res->index); + goto error; + } + + mdss_pll_resource_enable(hdmi_res, false); + pr_debug("HDMI PLL enabled\n"); +error: + return rc; +} + +void hdmi_vco_unprepare_28lpm(struct clk_hw *hw) +{ + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk_hw(hw); + struct mdss_pll_resources *hdmi_res = vco->priv; + + if (!hdmi_res) { + pr_err("Invalid input parameter\n"); + return; + } + + if (!hdmi_res->pll_on && + mdss_pll_resource_enable(hdmi_res, true)) { + pr_err("pll resource can't be enabled\n"); + return; + } + + hdmi_res->vco_cached_rate = clk_hw_get_rate(hw); + hdmi_pll_disable_28lpm(hw); + + hdmi_res->handoff_resources = false; + mdss_pll_resource_enable(hdmi_res, false); + hdmi_res->pll_on = false; + + pr_debug("HDMI PLL disabled\n"); +} + + +unsigned long hdmi_vco_recalc_rate_28lpm(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk_hw(hw); + struct mdss_pll_resources *hdmi_pll_res = vco->priv; + u64 vco_rate = 0; + + if (!hdmi_pll_res) { + pr_err("dsi pll resources not available\n"); + return 0; + } + + if (hdmi_pll_res->vco_current_rate) { + vco_rate = (unsigned long)hdmi_pll_res->vco_current_rate; + pr_debug("vco_rate=%ld\n", vco_rate); + return vco_rate; + } + + if (is_gdsc_disabled(hdmi_pll_res)) + return 0; + + if (mdss_pll_resource_enable(hdmi_pll_res, true)) { + pr_err("Failed to enable hdmi pll resources\n"); + return 0; + } + + if (hdmi_pll_lock_status(hdmi_pll_res)) { + hdmi_pll_res->handoff_resources = true; + hdmi_pll_res->pll_on = true; + vco_rate = hdmi_vco_get_rate(vco); + } else { + hdmi_pll_res->handoff_resources = false; + mdss_pll_resource_enable(hdmi_pll_res, false); + } + + pr_debug("vco_rate = %ld\n", vco_rate); + + return (unsigned long)vco_rate; +} + +static int hdmi_mux_set_parent(void *context, unsigned int reg, + unsigned int mux_sel) +{ + struct mdss_pll_resources *hdmi_pll_res = context; + int rc = 0; + u32 reg_val = 0; + + rc = mdss_pll_resource_enable(hdmi_pll_res, true); + if (rc) { + pr_err("Failed to enable hdmi pll resources\n"); + return rc; + } + + pr_debug("mux_sel = %d\n", mux_sel); + + reg_val = MDSS_PLL_REG_R(hdmi_pll_res->pll_base, + HDMI_PHY_PLL_REFCLK_CFG); + reg_val &= ~0x70; + reg_val |= (mux_sel & 0x70); + pr_debug("pll_refclk_cfg = 0x%x\n", reg_val); + MDSS_PLL_REG_W(hdmi_pll_res->pll_base, + HDMI_PHY_PLL_REFCLK_CFG, reg_val); + + (void)mdss_pll_resource_enable(hdmi_pll_res, false); + + return 0; +} + +static int hdmi_mux_get_parent(void *context, unsigned int reg, + unsigned int *val) +{ + int rc = 0; + int mux_sel = 0; + struct mdss_pll_resources *hdmi_pll_res = context; + + rc = mdss_pll_resource_enable(hdmi_pll_res, true); + if (rc) { + *val = 0; + pr_err("Failed to enable hdmi pll resources\n"); + } else { + mux_sel = MDSS_PLL_REG_R(hdmi_pll_res->pll_base, + HDMI_PHY_PLL_REFCLK_CFG); + mux_sel &= 0x70; + *val = mux_sel; + pr_debug("mux_sel = %d\n", *val); + } + + (void)mdss_pll_resource_enable(hdmi_pll_res, false); + + return rc; +} + +static struct regmap_config hdmi_pll_28lpm_cfg = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x49c, +}; + +static struct regmap_bus hdmi_pclk_src_mux_regmap_ops = { + .reg_write = hdmi_mux_set_parent, + .reg_read = hdmi_mux_get_parent, +}; + +/* Op structures */ +static const struct clk_ops hdmi_28lpm_vco_clk_ops = { + .recalc_rate = hdmi_vco_recalc_rate_28lpm, + .set_rate = hdmi_vco_set_rate_28lpm, + .round_rate = hdmi_vco_round_rate_28lpm, + .prepare = hdmi_vco_prepare_28lpm, + .unprepare = hdmi_vco_unprepare_28lpm, +}; + +static struct hdmi_pll_vco_clk hdmi_vco_clk = { + .min_rate = 540000000, + .max_rate = 1125000000, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_vco_clk", + .parent_names = (const char *[]){ "cxo" }, + .num_parents = 1, + .ops = &hdmi_28lpm_vco_clk_ops, + }, +}; + +static struct clk_fixed_factor hdmi_vco_divsel_one_clk_src = { + .div = 1, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "hdmi_vco_divsel_one_clk_src", + .parent_names = + (const char *[]){ "hdmi_vco_clk" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor hdmi_vco_divsel_two_clk_src = { + .div = 2, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "hdmi_vco_divsel_two_clk_src", + .parent_names = + (const char *[]){ "hdmi_vco_clk" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor hdmi_vco_divsel_four_clk_src = { + .div = 4, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "hdmi_vco_divsel_four_clk_src", + .parent_names = + (const char *[]){ "hdmi_vco_clk" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor hdmi_vco_divsel_six_clk_src = { + .div = 6, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "hdmi_vco_divsel_six_clk_src", + .parent_names = + (const char *[]){ "hdmi_vco_clk" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_regmap_mux hdmi_pclk_src_mux = { + .reg = HDMI_PHY_PLL_REFCLK_CFG, + .shift = 4, + .width = 2, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pclk_src_mux", + .parent_names = + (const char *[]){"hdmi_vco_divsel_one_clk_src", + "hdmi_vco_divsel_two_clk_src", + "hdmi_vco_divsel_six_clk_src", + "hdmi_vco_divsel_four_clk_src"}, + .num_parents = 4, + .ops = &clk_regmap_mux_closest_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_fixed_factor hdmi_pclk_src = { + .div = 5, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "hdmi_phy_pll_clk", + .parent_names = + (const char *[]){ "hdmi_pclk_src_mux" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_hw *mdss_hdmi_pllcc_28lpm[] = { + [HDMI_VCO_CLK] = &hdmi_vco_clk.hw, + [HDMI_VCO_DIVIDED_1_CLK_SRC] = &hdmi_vco_divsel_one_clk_src.hw, + [HDMI_VCO_DIVIDED_TWO_CLK_SRC] = &hdmi_vco_divsel_two_clk_src.hw, + [HDMI_VCO_DIVIDED_FOUR_CLK_SRC] = &hdmi_vco_divsel_four_clk_src.hw, + [HDMI_VCO_DIVIDED_SIX_CLK_SRC] = &hdmi_vco_divsel_six_clk_src.hw, + [HDMI_PCLK_SRC_MUX] = &hdmi_pclk_src_mux.clkr.hw, + [HDMI_PCLK_SRC] = &hdmi_pclk_src.hw, +}; + +int hdmi_pll_clock_register_28lpm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + int rc = -ENOTSUPP, i; + struct clk *clk; + struct clk_onecell_data *clk_data; + int num_clks = ARRAY_SIZE(mdss_hdmi_pllcc_28lpm); + struct regmap *regmap; + + if (!pdev || !pdev->dev.of_node || + !pll_res || !pll_res->pll_base) { + pr_err("Invalid input parameters\n"); + return -EPROBE_DEFER; + } + + clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data), + GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->clks = devm_kzalloc(&pdev->dev, (num_clks * + sizeof(struct clk *)), GFP_KERNEL); + if (!clk_data->clks) { + devm_kfree(&pdev->dev, clk_data); + return -ENOMEM; + } + clk_data->clk_num = num_clks; + + /* Set client data for vco, mux and div clocks */ + regmap = devm_regmap_init(&pdev->dev, &hdmi_pclk_src_mux_regmap_ops, + pll_res, &hdmi_pll_28lpm_cfg); + hdmi_pclk_src_mux.clkr.regmap = regmap; + + hdmi_vco_clk.priv = pll_res; + + for (i = HDMI_VCO_CLK; i <= HDMI_PCLK_SRC; i++) { + pr_debug("reg clk: %d index: %d\n", i, pll_res->index); + clk = devm_clk_register(&pdev->dev, + mdss_hdmi_pllcc_28lpm[i]); + if (IS_ERR(clk)) { + pr_err("clk registration failed for HDMI: %d\n", + pll_res->index); + rc = -EINVAL; + goto clk_reg_fail; + } + clk_data->clks[i] = clk; + } + + rc = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, clk_data); + if (rc) { + pr_err("%s: Clock register failed rc=%d\n", __func__, rc); + rc = -EPROBE_DEFER; + } else { + pr_debug("%s SUCCESS\n", __func__); + rc = 0; + } + return rc; +clk_reg_fail: + devm_kfree(&pdev->dev, clk_data->clks); + devm_kfree(&pdev->dev, clk_data); + return rc; +} diff --git a/drivers/clk/qcom/mdss/mdss-hdmi-pll.h b/drivers/clk/qcom/mdss/mdss-hdmi-pll.h index 5c73ed4714c3ef0596485d96409062058fdf4207..75f7fd3619e8ef7583782dc7ff748bec6d7a691e 100644 --- a/drivers/clk/qcom/mdss/mdss-hdmi-pll.h +++ b/drivers/clk/qcom/mdss/mdss-hdmi-pll.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -19,6 +19,7 @@ struct hdmi_pll_cfg { }; struct hdmi_pll_vco_clk { + struct clk_hw hw; unsigned long rate; /* current vco rate */ unsigned long min_rate; /* min vco rate */ unsigned long max_rate; /* max vco rate */ @@ -30,14 +31,16 @@ struct hdmi_pll_vco_clk { struct hdmi_pll_cfg *crctrl; void *priv; - struct clk c; }; -static inline struct hdmi_pll_vco_clk *to_hdmi_vco_clk(struct clk *clk) +static inline struct hdmi_pll_vco_clk *to_hdmi_vco_clk_hw(struct clk_hw *hw) { - return container_of(clk, struct hdmi_pll_vco_clk, c); + return container_of(hw, struct hdmi_pll_vco_clk, hw); } +int hdmi_pll_clock_register_28lpm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res); + int hdmi_pll_clock_register(struct platform_device *pdev, struct mdss_pll_resources *pll_res); diff --git a/drivers/clk/qcom/mdss/mdss-pll.c b/drivers/clk/qcom/mdss/mdss-pll.c index 50a2b722400031bf5eb34b573e743d34ccf7f080..d03c4e8ae233cb5c7375e8a989658ba296acb979 100644 --- a/drivers/clk/qcom/mdss/mdss-pll.c +++ b/drivers/clk/qcom/mdss/mdss-pll.c @@ -22,6 +22,7 @@ #include "mdss-pll.h" #include "mdss-dsi-pll.h" #include "mdss-dp-pll.h" +#include "mdss-hdmi-pll.h" int mdss_pll_resource_enable(struct mdss_pll_resources *pll_res, bool enable) { @@ -139,6 +140,8 @@ static int mdss_pll_resource_parse(struct platform_device *pdev, pll_res->pll_interface_type = MDSS_DSI_PLL_14NM; else if (!strcmp(compatible_stream, "qcom,mdss_dp_pll_14nm")) pll_res->pll_interface_type = MDSS_DP_PLL_14NM; + else if (!strcmp(compatible_stream, "qcom,mdss_hdmi_pll_28lpm")) + pll_res->pll_interface_type = MDSS_HDMI_PLL_28LPM; else goto err; @@ -182,6 +185,9 @@ static int mdss_pll_clock_register(struct platform_device *pdev, case MDSS_DP_PLL_14NM: rc = dp_pll_clock_register_14nm(pdev, pll_res); break; + case MDSS_HDMI_PLL_28LPM: + rc = hdmi_pll_clock_register_28lpm(pdev, pll_res); + break; case MDSS_UNKNOWN_PLL: default: rc = -EINVAL; @@ -415,6 +421,7 @@ static const struct of_device_id mdss_pll_dt_match[] = { {.compatible = "qcom,mdss_dsi_pll_28lpm"}, {.compatible = "qcom,mdss_dsi_pll_14nm"}, {.compatible = "qcom,mdss_dp_pll_14nm"}, + {.compatible = "qcom,mdss_hdmi_pll_28lpm"}, {} }; diff --git a/drivers/clk/qcom/mdss/mdss-pll.h b/drivers/clk/qcom/mdss/mdss-pll.h index 6bbde04494d5bdc98a63dacaa678d431b5a0c623..683753da97353354dea70b17a565e146603fbcec 100644 --- a/drivers/clk/qcom/mdss/mdss-pll.h +++ b/drivers/clk/qcom/mdss/mdss-pll.h @@ -48,6 +48,7 @@ enum { MDSS_DSI_PLL_28LPM, MDSS_DSI_PLL_14NM, MDSS_DP_PLL_14NM, + MDSS_HDMI_PLL_28LPM, MDSS_UNKNOWN_PLL, }; diff --git a/drivers/clk/qcom/npucc-sdmmagpie.c b/drivers/clk/qcom/npucc-sdmmagpie.c index efa104d29189123363793478e3703d8e867b1183..95f41fd3197d114f64acc839572f3f6905ac98fd 100644 --- a/drivers/clk/qcom/npucc-sdmmagpie.c +++ b/drivers/clk/qcom/npucc-sdmmagpie.c @@ -34,14 +34,14 @@ #include "clk-branch.h" #include "reset.h" #include "clk-alpha-pll.h" -#include "vdd-level.h" +#include "vdd-level-sdmmagpie.h" #define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } #define CRC_SID_FSM_CTRL 0x100c #define CRC_SID_FSM_CTRL_SETTING 0x800000 #define CRC_MND_CFG 0x1010 -#define CRC_MND_CFG_SETTING 0x15010 +#define CRC_MND_CFG_SETTING 0x15011 static DEFINE_VDD_REGULATORS(vdd_cx, VDD_NUM, 1, vdd_corner); @@ -73,6 +73,25 @@ static const char * const npu_cc_parent_names_0[] = { "core_bi_pll_test_se", }; +static const struct parent_map npu_cc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_NPU_CC_PLL1_OUT_EVEN, 1 }, + { P_NPU_CC_CRC_DIV, 2 }, + { P_GPLL0_OUT_MAIN, 4 }, + { P_GPLL0_OUT_MAIN_DIV, 5 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const npu_cc_parent_names_1[] = { + "bi_tcxo", + "npu_cc_pll1_out_even", + "npu_cc_crc_div", + "gcc_npu_gpll0_clk_src", + "gcc_npu_gpll0_div_clk_src", + "core_bi_pll_test_se", +}; + + static struct pll_vco fabia_vco[] = { { 249600000, 2000000000, 0 }, { 125000000, 1000000000, 1 }, @@ -180,14 +199,26 @@ static struct clk_alpha_pll_postdiv npu_cc_pll1_out_even = { }, }; +static struct clk_fixed_factor npu_cc_crc_div = { + .mult = 1, + .div = 2, + .hw.init = &(struct clk_init_data){ + .name = "npu_cc_crc_div", + .parent_names = (const char *[]){ "npu_cc_pll0_out_even" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + static const struct freq_tbl ftbl_npu_cc_cal_dp_clk_src[] = { F(19200000, P_BI_TCXO, 1, 0, 0), - F(300000000, P_NPU_CC_PLL0_OUT_EVEN, 2, 0, 0), - F(350000000, P_NPU_CC_PLL0_OUT_EVEN, 2, 0, 0), - F(400000000, P_NPU_CC_PLL0_OUT_EVEN, 2, 0, 0), - F(466500000, P_NPU_CC_PLL0_OUT_EVEN, 2, 0, 0), - F(600000000, P_NPU_CC_PLL0_OUT_EVEN, 2, 0, 0), - F(700000000, P_NPU_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(300000000, P_NPU_CC_CRC_DIV, 1, 0, 0), + F(350000000, P_NPU_CC_CRC_DIV, 1, 0, 0), + F(400000000, P_NPU_CC_CRC_DIV, 1, 0, 0), + F(466500000, P_NPU_CC_CRC_DIV, 1, 0, 0), + F(600000000, P_NPU_CC_CRC_DIV, 1, 0, 0), + F(700000000, P_NPU_CC_CRC_DIV, 1, 0, 0), { } }; @@ -195,12 +226,12 @@ static struct clk_rcg2 npu_cc_cal_dp_clk_src = { .cmd_rcgr = 0x1004, .mnd_width = 0, .hid_width = 5, - .parent_map = npu_cc_parent_map_0, + .parent_map = npu_cc_parent_map_1, .freq_tbl = ftbl_npu_cc_cal_dp_clk_src, .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "npu_cc_cal_dp_clk_src", - .parent_names = npu_cc_parent_names_0, + .parent_names = npu_cc_parent_names_1, .num_parents = 6, .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, @@ -624,6 +655,13 @@ static int npu_cc_sdmmagpie_probe(struct platform_device *pdev) clk_fabia_pll_configure(&npu_cc_pll0, regmap, &npu_cc_pll0_config); clk_fabia_pll_configure(&npu_cc_pll1, regmap, &npu_cc_pll1_config); + /* Register the fixed factor clock for CRC divide */ + ret = devm_clk_hw_register(&pdev->dev, &npu_cc_crc_div.hw); + if (ret) { + dev_err(&pdev->dev, "Failed to register CRC divide clock\n"); + return ret; + } + ret = qcom_cc_really_probe(pdev, &npu_cc_sdmmagpie_desc, regmap); if (ret) { dev_err(&pdev->dev, "Failed to register NPU CC clocks\n"); diff --git a/drivers/clk/qcom/vdd-level-sdmmagpie.h b/drivers/clk/qcom/vdd-level-sdmmagpie.h new file mode 100644 index 0000000000000000000000000000000000000000..1a4c5ccedb3bd9693f4e7b93212e5cb69778437a --- /dev/null +++ b/drivers/clk/qcom/vdd-level-sdmmagpie.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __DRIVERS_CLK_QCOM_VDD_LEVEL_SDMMAGPIE_H +#define __DRIVERS_CLK_QCOM_VDD_LEVEL_SDMMAGPIE_H + +#include +#include + +enum vdd_levels { + VDD_NONE, + VDD_MIN, /* MIN SVS */ + VDD_LOWER, /* SVS2 */ + VDD_LOW, /* SVS */ + VDD_LOW_L1, /* SVSL1 */ + VDD_NOMINAL, /* NOM */ + VDD_HIGH, /* TURBO */ + VDD_NUM, +}; + +static int vdd_corner[] = { + RPMH_REGULATOR_LEVEL_OFF, /* VDD_NONE */ + RPMH_REGULATOR_LEVEL_MIN_SVS, /* VDD_MIN */ + RPMH_REGULATOR_LEVEL_LOW_SVS, /* VDD_LOWER */ + RPMH_REGULATOR_LEVEL_SVS, /* VDD_LOW */ + RPMH_REGULATOR_LEVEL_SVS_L1, /* VDD_LOW_L1 */ + RPMH_REGULATOR_LEVEL_NOM, /* VDD_NOMINAL */ + RPMH_REGULATOR_LEVEL_TURBO, /* VDD_HIGH */ +}; + +#endif diff --git a/drivers/clk/qcom/videocc-sdmmagpie.c b/drivers/clk/qcom/videocc-sdmmagpie.c index 8d2d57f3104d54b6c7fa6eb73853f02a6dd15d84..922ef26b32aeb632f5241f36a2f9dbccadf83df1 100644 --- a/drivers/clk/qcom/videocc-sdmmagpie.c +++ b/drivers/clk/qcom/videocc-sdmmagpie.c @@ -32,7 +32,7 @@ #include "clk-rcg.h" #include "clk-branch.h" #include "clk-alpha-pll.h" -#include "vdd-level.h" +#include "vdd-level-sdmmagpie.h" #define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } @@ -68,7 +68,7 @@ static const struct parent_map video_cc_parent_map_2[] = { }; static const char * const video_cc_parent_names_2[] = { - "bi_tcxo", + "bi_tcxo_ao", "core_bi_pll_test_se", }; diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c index 6847120b61cdeff87b7de7995c412df5a7d6449c..3acf5f041e3c3cb0a2f17cbf4e8f3a14a4f1b586 100644 --- a/drivers/clk/rockchip/clk-rk3399.c +++ b/drivers/clk/rockchip/clk-rk3399.c @@ -630,7 +630,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { MUX(0, "clk_i2sout_src", mux_i2sch_p, CLK_SET_RATE_PARENT, RK3399_CLKSEL_CON(31), 0, 2, MFLAGS), COMPOSITE_NODIV(SCLK_I2S_8CH_OUT, "clk_i2sout", mux_i2sout_p, CLK_SET_RATE_PARENT, - RK3399_CLKSEL_CON(30), 8, 2, MFLAGS, + RK3399_CLKSEL_CON(31), 2, 1, MFLAGS, RK3399_CLKGATE_CON(8), 12, GFLAGS), /* uart */ @@ -1522,6 +1522,7 @@ static const char *const rk3399_pmucru_critical_clocks[] __initconst = { "pclk_pmu_src", "fclk_cm0s_src_pmu", "clk_timer_src_pmu", + "pclk_rkpwm_pmu", }; static void __init rk3399_clk_init(struct device_node *np) diff --git a/drivers/clk/sunxi-ng/ccu-sun4i-a10.c b/drivers/clk/sunxi-ng/ccu-sun4i-a10.c index 286b0049b7b604e461c8c2d1c85b13addf161686..a48fde191c0ae0e96824311e10bf590d364f1afb 100644 --- a/drivers/clk/sunxi-ng/ccu-sun4i-a10.c +++ b/drivers/clk/sunxi-ng/ccu-sun4i-a10.c @@ -223,7 +223,7 @@ static struct ccu_mux cpu_clk = { .hw.init = CLK_HW_INIT_PARENTS("cpu", cpu_parents, &ccu_mux_ops, - CLK_IS_CRITICAL), + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), } }; diff --git a/drivers/clk/tegra/clk-bpmp.c b/drivers/clk/tegra/clk-bpmp.c index 638ace64033b92a54b930c4bdf1be65550241099..6c933b0e29a3bfb384a9fb24c369d0ff1ef7fbd4 100644 --- a/drivers/clk/tegra/clk-bpmp.c +++ b/drivers/clk/tegra/clk-bpmp.c @@ -581,9 +581,15 @@ static struct clk_hw *tegra_bpmp_clk_of_xlate(struct of_phandle_args *clkspec, unsigned int id = clkspec->args[0], i; struct tegra_bpmp *bpmp = data; - for (i = 0; i < bpmp->num_clocks; i++) - if (bpmp->clocks[i]->id == id) - return &bpmp->clocks[i]->hw; + for (i = 0; i < bpmp->num_clocks; i++) { + struct tegra_bpmp_clk *clk = bpmp->clocks[i]; + + if (!clk) + continue; + + if (clk->id == id) + return &clk->hw; + } return NULL; } diff --git a/drivers/clocksource/timer-atmel-pit.c b/drivers/clocksource/timer-atmel-pit.c index ec8a4376f74fb4f9da1f369a968df457064315e2..2fab18fae4fcbbeeb44cfbc4f2517258cd3dc505 100644 --- a/drivers/clocksource/timer-atmel-pit.c +++ b/drivers/clocksource/timer-atmel-pit.c @@ -180,26 +180,29 @@ static int __init at91sam926x_pit_dt_init(struct device_node *node) data->base = of_iomap(node, 0); if (!data->base) { pr_err("Could not map PIT address\n"); - return -ENXIO; + ret = -ENXIO; + goto exit; } data->mck = of_clk_get(node, 0); if (IS_ERR(data->mck)) { pr_err("Unable to get mck clk\n"); - return PTR_ERR(data->mck); + ret = PTR_ERR(data->mck); + goto exit; } ret = clk_prepare_enable(data->mck); if (ret) { pr_err("Unable to enable mck\n"); - return ret; + goto exit; } /* Get the interrupts property */ data->irq = irq_of_parse_and_map(node, 0); if (!data->irq) { pr_err("Unable to get IRQ from DT\n"); - return -EINVAL; + ret = -EINVAL; + goto exit; } /* @@ -227,7 +230,7 @@ static int __init at91sam926x_pit_dt_init(struct device_node *node) ret = clocksource_register_hz(&data->clksrc, pit_rate); if (ret) { pr_err("Failed to register clocksource\n"); - return ret; + goto exit; } /* Set up irq handler */ @@ -236,7 +239,8 @@ static int __init at91sam926x_pit_dt_init(struct device_node *node) "at91_tick", data); if (ret) { pr_err("Unable to setup IRQ\n"); - return ret; + clocksource_unregister(&data->clksrc); + goto exit; } /* Set up and register clockevents */ @@ -254,6 +258,10 @@ static int __init at91sam926x_pit_dt_init(struct device_node *node) clockevents_register_device(&data->clkevt); return 0; + +exit: + kfree(data); + return ret; } TIMER_OF_DECLARE(at91sam926x_pit, "atmel,at91sam9260-pit", at91sam926x_pit_dt_init); diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 43e14bb512c8da4cd2c0f8a73e37a1fe1205a170..6a16d22bc6043de0b01384e9623569244a1628f1 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -555,12 +555,20 @@ EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_stop); void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy) { - struct policy_dbs_info *policy_dbs = policy->governor_data; + struct policy_dbs_info *policy_dbs; + + /* Protect gov->gdbs_data against cpufreq_dbs_governor_exit() */ + mutex_lock(&gov_dbs_data_mutex); + policy_dbs = policy->governor_data; + if (!policy_dbs) + goto out; mutex_lock(&policy_dbs->update_mutex); cpufreq_policy_apply_limits(policy); gov_update_sample_delay(policy_dbs, 0); - mutex_unlock(&policy_dbs->update_mutex); + +out: + mutex_unlock(&gov_dbs_data_mutex); } EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_limits); diff --git a/drivers/cpuidle/lpm-levels-of.c b/drivers/cpuidle/lpm-levels-of.c index 5309df474bd177813e5f95d63f6cb9c3efe0f4b6..87a8954d84a8f03dcf96150ed3c3fa575e072540 100644 --- a/drivers/cpuidle/lpm-levels-of.c +++ b/drivers/cpuidle/lpm-levels-of.c @@ -548,11 +548,11 @@ static int parse_cpu(struct device_node *node, struct lpm_cpu *cpu) key = "qcom,reset-level"; ret = of_property_read_u32(n, key, &l->reset_level); + of_node_put(n); if (ret == -EINVAL) l->reset_level = LPM_RESET_LVL_NONE; else if (ret) return ret; - of_node_put(n); } for (i = 1; i < cpu->nlevels; i++) @@ -661,7 +661,7 @@ struct lpm_cluster *parse_cluster(struct device_node *node, ret = parse_cluster_params(node, c); if (ret) - goto failed_parse_params; + return NULL; INIT_LIST_HEAD(&c->child); INIT_LIST_HEAD(&c->cpu); @@ -671,47 +671,36 @@ struct lpm_cluster *parse_cluster(struct device_node *node, for_each_child_of_node(node, n) { - if (!n->name) - continue; - - key = "qcom,pm-cluster-level"; - if (!of_node_cmp(n->name, key)) { - if (parse_cluster_level(n, c)) { - of_node_put(n); - goto failed_parse_cluster; - } + if (!n->name) { of_node_put(n); continue; } - key = "qcom,pm-cluster"; - if (!of_node_cmp(n->name, key)) { + if (!of_node_cmp(n->name, "qcom,pm-cluster-level")) { + key = "qcom,pm-cluster-level"; + if (parse_cluster_level(n, c)) + goto failed_parse_cluster; + } else if (!of_node_cmp(n->name, "qcom,pm-cluster")) { struct lpm_cluster *child; + key = "qcom,pm-cluster"; child = parse_cluster(n, c); - if (!child) { - of_node_put(n); + if (!child) goto failed_parse_cluster; - } list_add(&child->list, &c->child); cpumask_or(&c->child_cpus, &c->child_cpus, &child->child_cpus); c->aff_level = child->aff_level + 1; - of_node_put(n); - continue; - } - - key = "qcom,pm-cpu"; - if (!of_node_cmp(n->name, key)) { - if (parse_cpu_levels(n, c)) { - of_node_put(n); + } else if (!of_node_cmp(n->name, "qcom,pm-cpu")) { + key = "qcom,pm-cpu"; + if (parse_cpu_levels(n, c)) goto failed_parse_cluster; - } c->aff_level = 1; - of_node_put(n); } + + of_node_put(n); } if (cpumask_intersects(&c->child_cpus, cpu_online_mask)) @@ -729,13 +718,13 @@ struct lpm_cluster *parse_cluster(struct device_node *node, failed_parse_cluster: pr_err("Failed parse cluster:%s\n", key); + of_node_put(n); if (parent) list_del(&c->list); free_cluster_node(c); -failed_parse_params: - pr_err("Failed parse params\n"); return NULL; } + struct lpm_cluster *lpm_of_parse_cluster(struct platform_device *pdev) { struct device_node *top = NULL; diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index b6c5f7b3facf68951ef5cbcbde158d621a2cce11..16679458edb31516e9730a790253879c06a8c7ec 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -339,6 +339,11 @@ static void histtimer_cancel(void) { unsigned int cpu = raw_smp_processor_id(); struct hrtimer *cpu_histtimer = &per_cpu(histtimer, cpu); + ktime_t time_rem; + + time_rem = hrtimer_get_remaining(cpu_histtimer); + if (ktime_to_us(time_rem) <= 0) + return; hrtimer_try_to_cancel(cpu_histtimer); } @@ -384,11 +389,21 @@ static void clusttimer_cancel(void) { int cpu = raw_smp_processor_id(); struct lpm_cluster *cluster = per_cpu(cpu_lpm, cpu)->parent; + ktime_t time_rem; + + time_rem = hrtimer_get_remaining(&cluster->histtimer); + if (ktime_to_us(time_rem) > 0) + hrtimer_try_to_cancel(&cluster->histtimer); + + if (cluster->parent) { + time_rem = hrtimer_get_remaining( + &cluster->parent->histtimer); - hrtimer_try_to_cancel(&cluster->histtimer); + if (ktime_to_us(time_rem) <= 0) + return; - if (cluster->parent) hrtimer_try_to_cancel(&cluster->parent->histtimer); + } } static enum hrtimer_restart clusttimer_fn(struct hrtimer *h) @@ -1052,7 +1067,7 @@ static int cluster_configure(struct lpm_cluster *cluster, int idx, * LPMs(XO and Vmin). */ if (!from_idle) - clock_debug_print_enabled(); + clock_debug_print_enabled(true); cpu = get_next_online_cpu(from_idle); cpumask_copy(&cpumask, cpumask_of(cpu)); @@ -1400,11 +1415,11 @@ static int lpm_cpuidle_enter(struct cpuidle_device *dev, dev->last_residency = ktime_us_delta(ktime_get(), start); update_history(dev, idx); trace_cpu_idle_exit(idx, success); - local_irq_enable(); if (lpm_prediction && cpu->lpm_prediction) { histtimer_cancel(); clusttimer_cancel(); } + local_irq_enable(); return idx; } diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index a8a2a271b63d21224214e153545c09b25576953c..43fe195f6dca5353844fc654bb4ef3073fe6b7ad 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -1511,8 +1511,8 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request edesc->src_nents = src_nents; edesc->dst_nents = dst_nents; edesc->sec4_sg_bytes = sec4_sg_bytes; - edesc->sec4_sg = (void *)edesc + sizeof(struct ablkcipher_edesc) + - desc_bytes; + edesc->sec4_sg = (struct sec4_sg_entry *)((u8 *)edesc->hw_desc + + desc_bytes); edesc->iv_dir = DMA_TO_DEVICE; /* Make sure IV is located in a DMAable area */ @@ -1715,8 +1715,8 @@ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( edesc->src_nents = src_nents; edesc->dst_nents = dst_nents; edesc->sec4_sg_bytes = sec4_sg_bytes; - edesc->sec4_sg = (void *)edesc + sizeof(struct ablkcipher_edesc) + - desc_bytes; + edesc->sec4_sg = (struct sec4_sg_entry *)((u8 *)edesc->hw_desc + + desc_bytes); edesc->iv_dir = DMA_FROM_DEVICE; /* Make sure IV is located in a DMAable area */ diff --git a/drivers/crypto/caam/caamalg_qi.c b/drivers/crypto/caam/caamalg_qi.c index e7966e37a5aaeeb9fe259b5a2c3d460892b14e85..ecc6d755d3c1b9131f8c43e433229e96cf667c6a 100644 --- a/drivers/crypto/caam/caamalg_qi.c +++ b/drivers/crypto/caam/caamalg_qi.c @@ -350,10 +350,8 @@ static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, int ret = 0; if (keylen != 2 * AES_MIN_KEY_SIZE && keylen != 2 * AES_MAX_KEY_SIZE) { - crypto_ablkcipher_set_flags(ablkcipher, - CRYPTO_TFM_RES_BAD_KEY_LEN); dev_err(jrdev, "key size mismatch\n"); - return -EINVAL; + goto badkey; } memcpy(ctx->key, key, keylen); @@ -388,7 +386,7 @@ static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, return ret; badkey: crypto_ablkcipher_set_flags(ablkcipher, CRYPTO_TFM_RES_BAD_KEY_LEN); - return 0; + return -EINVAL; } /* diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c index 7ff4a25440acd9813d4fb19b9ef7355d6765451d..6f3f81bb880b505797bd69bd7288083c1ceef029 100644 --- a/drivers/crypto/caam/caampkc.c +++ b/drivers/crypto/caam/caampkc.c @@ -71,8 +71,8 @@ static void rsa_priv_f2_unmap(struct device *dev, struct rsa_edesc *edesc, dma_unmap_single(dev, pdb->d_dma, key->d_sz, DMA_TO_DEVICE); dma_unmap_single(dev, pdb->p_dma, p_sz, DMA_TO_DEVICE); dma_unmap_single(dev, pdb->q_dma, q_sz, DMA_TO_DEVICE); - dma_unmap_single(dev, pdb->tmp1_dma, p_sz, DMA_TO_DEVICE); - dma_unmap_single(dev, pdb->tmp2_dma, q_sz, DMA_TO_DEVICE); + dma_unmap_single(dev, pdb->tmp1_dma, p_sz, DMA_BIDIRECTIONAL); + dma_unmap_single(dev, pdb->tmp2_dma, q_sz, DMA_BIDIRECTIONAL); } static void rsa_priv_f3_unmap(struct device *dev, struct rsa_edesc *edesc, @@ -90,8 +90,8 @@ static void rsa_priv_f3_unmap(struct device *dev, struct rsa_edesc *edesc, dma_unmap_single(dev, pdb->dp_dma, p_sz, DMA_TO_DEVICE); dma_unmap_single(dev, pdb->dq_dma, q_sz, DMA_TO_DEVICE); dma_unmap_single(dev, pdb->c_dma, p_sz, DMA_TO_DEVICE); - dma_unmap_single(dev, pdb->tmp1_dma, p_sz, DMA_TO_DEVICE); - dma_unmap_single(dev, pdb->tmp2_dma, q_sz, DMA_TO_DEVICE); + dma_unmap_single(dev, pdb->tmp1_dma, p_sz, DMA_BIDIRECTIONAL); + dma_unmap_single(dev, pdb->tmp2_dma, q_sz, DMA_BIDIRECTIONAL); } /* RSA Job Completion handler */ @@ -417,13 +417,13 @@ static int set_rsa_priv_f2_pdb(struct akcipher_request *req, goto unmap_p; } - pdb->tmp1_dma = dma_map_single(dev, key->tmp1, p_sz, DMA_TO_DEVICE); + pdb->tmp1_dma = dma_map_single(dev, key->tmp1, p_sz, DMA_BIDIRECTIONAL); if (dma_mapping_error(dev, pdb->tmp1_dma)) { dev_err(dev, "Unable to map RSA tmp1 memory\n"); goto unmap_q; } - pdb->tmp2_dma = dma_map_single(dev, key->tmp2, q_sz, DMA_TO_DEVICE); + pdb->tmp2_dma = dma_map_single(dev, key->tmp2, q_sz, DMA_BIDIRECTIONAL); if (dma_mapping_error(dev, pdb->tmp2_dma)) { dev_err(dev, "Unable to map RSA tmp2 memory\n"); goto unmap_tmp1; @@ -451,7 +451,7 @@ static int set_rsa_priv_f2_pdb(struct akcipher_request *req, return 0; unmap_tmp1: - dma_unmap_single(dev, pdb->tmp1_dma, p_sz, DMA_TO_DEVICE); + dma_unmap_single(dev, pdb->tmp1_dma, p_sz, DMA_BIDIRECTIONAL); unmap_q: dma_unmap_single(dev, pdb->q_dma, q_sz, DMA_TO_DEVICE); unmap_p: @@ -504,13 +504,13 @@ static int set_rsa_priv_f3_pdb(struct akcipher_request *req, goto unmap_dq; } - pdb->tmp1_dma = dma_map_single(dev, key->tmp1, p_sz, DMA_TO_DEVICE); + pdb->tmp1_dma = dma_map_single(dev, key->tmp1, p_sz, DMA_BIDIRECTIONAL); if (dma_mapping_error(dev, pdb->tmp1_dma)) { dev_err(dev, "Unable to map RSA tmp1 memory\n"); goto unmap_qinv; } - pdb->tmp2_dma = dma_map_single(dev, key->tmp2, q_sz, DMA_TO_DEVICE); + pdb->tmp2_dma = dma_map_single(dev, key->tmp2, q_sz, DMA_BIDIRECTIONAL); if (dma_mapping_error(dev, pdb->tmp2_dma)) { dev_err(dev, "Unable to map RSA tmp2 memory\n"); goto unmap_tmp1; @@ -538,7 +538,7 @@ static int set_rsa_priv_f3_pdb(struct akcipher_request *req, return 0; unmap_tmp1: - dma_unmap_single(dev, pdb->tmp1_dma, p_sz, DMA_TO_DEVICE); + dma_unmap_single(dev, pdb->tmp1_dma, p_sz, DMA_BIDIRECTIONAL); unmap_qinv: dma_unmap_single(dev, pdb->c_dma, p_sz, DMA_TO_DEVICE); unmap_dq: diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c index d258953ff488331486334f8fc24a99c1bc5d0ca1..7fa1be1845535cb5b015fd35f8173cf0f080014c 100644 --- a/drivers/crypto/caam/jr.c +++ b/drivers/crypto/caam/jr.c @@ -190,7 +190,8 @@ static void caam_jr_dequeue(unsigned long devarg) BUG_ON(CIRC_CNT(head, tail + i, JOBR_DEPTH) <= 0); /* Unmap just-run descriptor so we can post-process */ - dma_unmap_single(dev, jrp->outring[hw_idx].desc, + dma_unmap_single(dev, + caam_dma_to_cpu(jrp->outring[hw_idx].desc), jrp->entinfo[sw_idx].desc_size, DMA_TO_DEVICE); diff --git a/drivers/crypto/cavium/nitrox/nitrox_dev.h b/drivers/crypto/cavium/nitrox/nitrox_dev.h index 9a476bb6d4c7eace932edb09b040098eccee7aa0..af596455b420f60d68096b8f2d4e9c71745785fc 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_dev.h +++ b/drivers/crypto/cavium/nitrox/nitrox_dev.h @@ -35,6 +35,7 @@ struct nitrox_cmdq { /* requests in backlog queues */ atomic_t backlog_count; + int write_idx; /* command size 32B/64B */ u8 instr_size; u8 qno; @@ -87,7 +88,7 @@ struct nitrox_bh { struct bh_data *slc; }; -/* NITROX-5 driver state */ +/* NITROX-V driver state */ #define NITROX_UCODE_LOADED 0 #define NITROX_READY 1 diff --git a/drivers/crypto/cavium/nitrox/nitrox_lib.c b/drivers/crypto/cavium/nitrox/nitrox_lib.c index 4fdc921ba611b94b9a8d14e3a657a63497a4cce9..9906c00866476a33c80ba740563d60afaaf05697 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_lib.c +++ b/drivers/crypto/cavium/nitrox/nitrox_lib.c @@ -36,6 +36,7 @@ static int cmdq_common_init(struct nitrox_cmdq *cmdq) cmdq->head = PTR_ALIGN(cmdq->head_unaligned, PKT_IN_ALIGN); cmdq->dma = PTR_ALIGN(cmdq->dma_unaligned, PKT_IN_ALIGN); cmdq->qsize = (qsize + PKT_IN_ALIGN); + cmdq->write_idx = 0; spin_lock_init(&cmdq->response_lock); spin_lock_init(&cmdq->cmdq_lock); diff --git a/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c b/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c index 4addc238a6ef361db59cf49359d96ea8fae98f9a..4adf28176a4e439c79f238b1232e7361dfc6207d 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c +++ b/drivers/crypto/cavium/nitrox/nitrox_reqmgr.c @@ -43,6 +43,16 @@ * Invalid flag options in AES-CCM IV. */ +static inline int incr_index(int index, int count, int max) +{ + if ((index + count) >= max) + index = index + count - max; + else + index += count; + + return index; +} + /** * dma_free_sglist - unmap and free the sg lists. * @ndev: N5 device @@ -427,30 +437,29 @@ static void post_se_instr(struct nitrox_softreq *sr, struct nitrox_cmdq *cmdq) { struct nitrox_device *ndev = sr->ndev; - union nps_pkt_in_instr_baoff_dbell pkt_in_baoff_dbell; - u64 offset; + int idx; u8 *ent; spin_lock_bh(&cmdq->cmdq_lock); - /* get the next write offset */ - offset = NPS_PKT_IN_INSTR_BAOFF_DBELLX(cmdq->qno); - pkt_in_baoff_dbell.value = nitrox_read_csr(ndev, offset); + idx = cmdq->write_idx; /* copy the instruction */ - ent = cmdq->head + pkt_in_baoff_dbell.s.aoff; + ent = cmdq->head + (idx * cmdq->instr_size); memcpy(ent, &sr->instr, cmdq->instr_size); - /* flush the command queue updates */ - dma_wmb(); - sr->tstamp = jiffies; atomic_set(&sr->status, REQ_POSTED); response_list_add(sr, cmdq); + sr->tstamp = jiffies; + /* flush the command queue updates */ + dma_wmb(); /* Ring doorbell with count 1 */ writeq(1, cmdq->dbell_csr_addr); /* orders the doorbell rings */ mmiowb(); + cmdq->write_idx = incr_index(idx, 1, ndev->qlen); + spin_unlock_bh(&cmdq->cmdq_lock); } @@ -460,6 +469,9 @@ static int post_backlog_cmds(struct nitrox_cmdq *cmdq) struct nitrox_softreq *sr, *tmp; int ret = 0; + if (!atomic_read(&cmdq->backlog_count)) + return 0; + spin_lock_bh(&cmdq->backlog_lock); list_for_each_entry_safe(sr, tmp, &cmdq->backlog_head, backlog) { @@ -467,7 +479,7 @@ static int post_backlog_cmds(struct nitrox_cmdq *cmdq) /* submit until space available */ if (unlikely(cmdq_full(cmdq, ndev->qlen))) { - ret = -EBUSY; + ret = -ENOSPC; break; } /* delete from backlog list */ @@ -492,23 +504,20 @@ static int nitrox_enqueue_request(struct nitrox_softreq *sr) { struct nitrox_cmdq *cmdq = sr->cmdq; struct nitrox_device *ndev = sr->ndev; - int ret = -EBUSY; + + /* try to post backlog requests */ + post_backlog_cmds(cmdq); if (unlikely(cmdq_full(cmdq, ndev->qlen))) { if (!(sr->flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) - return -EAGAIN; - + return -ENOSPC; + /* add to backlog list */ backlog_list_add(sr, cmdq); - } else { - ret = post_backlog_cmds(cmdq); - if (ret) { - backlog_list_add(sr, cmdq); - return ret; - } - post_se_instr(sr, cmdq); - ret = -EINPROGRESS; + return -EBUSY; } - return ret; + post_se_instr(sr, cmdq); + + return -EINPROGRESS; } /** @@ -625,11 +634,9 @@ int nitrox_process_se_request(struct nitrox_device *ndev, */ sr->instr.fdata[0] = *((u64 *)&req->gph); sr->instr.fdata[1] = 0; - /* flush the soft_req changes before posting the cmd */ - wmb(); ret = nitrox_enqueue_request(sr); - if (ret == -EAGAIN) + if (ret == -ENOSPC) goto send_fail; return ret; diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c index 0e81607018331a2fe0823463b05efa8a0357fd81..bb7b59fc5c08b0b5417ccac58af879aab6edce5b 100644 --- a/drivers/crypto/chelsio/chcr_algo.c +++ b/drivers/crypto/chelsio/chcr_algo.c @@ -384,7 +384,8 @@ static inline int is_hmac(struct crypto_tfm *tfm) static void write_phys_cpl(struct cpl_rx_phys_dsgl *phys_cpl, struct scatterlist *sg, - struct phys_sge_parm *sg_param) + struct phys_sge_parm *sg_param, + int pci_chan_id) { struct phys_sge_pairs *to; unsigned int len = 0, left_size = sg_param->obsize; @@ -402,6 +403,7 @@ static void write_phys_cpl(struct cpl_rx_phys_dsgl *phys_cpl, phys_cpl->rss_hdr_int.opcode = CPL_RX_PHYS_ADDR; phys_cpl->rss_hdr_int.qid = htons(sg_param->qid); phys_cpl->rss_hdr_int.hash_val = 0; + phys_cpl->rss_hdr_int.channel = pci_chan_id; to = (struct phys_sge_pairs *)((unsigned char *)phys_cpl + sizeof(struct cpl_rx_phys_dsgl)); for (i = 0; nents && left_size; to++) { @@ -418,7 +420,8 @@ static void write_phys_cpl(struct cpl_rx_phys_dsgl *phys_cpl, static inline int map_writesg_phys_cpl(struct device *dev, struct cpl_rx_phys_dsgl *phys_cpl, struct scatterlist *sg, - struct phys_sge_parm *sg_param) + struct phys_sge_parm *sg_param, + int pci_chan_id) { if (!sg || !sg_param->nents) return -EINVAL; @@ -428,7 +431,7 @@ static inline int map_writesg_phys_cpl(struct device *dev, pr_err("CHCR : DMA mapping failed\n"); return -EINVAL; } - write_phys_cpl(phys_cpl, sg, sg_param); + write_phys_cpl(phys_cpl, sg, sg_param, pci_chan_id); return 0; } @@ -608,7 +611,7 @@ static inline void create_wreq(struct chcr_context *ctx, is_iv ? iv_loc : IV_NOP, !!lcb, ctx->tx_qidx); - chcr_req->ulptx.cmd_dest = FILL_ULPTX_CMD_DEST(ctx->dev->tx_channel_id, + chcr_req->ulptx.cmd_dest = FILL_ULPTX_CMD_DEST(ctx->tx_chan_id, qid); chcr_req->ulptx.len = htonl((DIV_ROUND_UP((calc_tx_flits_ofld(skb) * 8), 16) - ((sizeof(chcr_req->wreq)) >> 4))); @@ -698,7 +701,8 @@ static struct sk_buff *create_cipher_wr(struct cipher_wr_param *wrparam) sg_param.obsize = wrparam->bytes; sg_param.qid = wrparam->qid; error = map_writesg_phys_cpl(&u_ctx->lldi.pdev->dev, phys_cpl, - reqctx->dst, &sg_param); + reqctx->dst, &sg_param, + ctx->pci_chan_id); if (error) goto map_fail1; @@ -1228,16 +1232,23 @@ static int chcr_device_init(struct chcr_context *ctx) adap->vres.ncrypto_fc); rxq_perchan = u_ctx->lldi.nrxq / u_ctx->lldi.nchan; txq_perchan = ntxq / u_ctx->lldi.nchan; - rxq_idx = ctx->dev->tx_channel_id * rxq_perchan; - rxq_idx += id % rxq_perchan; - txq_idx = ctx->dev->tx_channel_id * txq_perchan; - txq_idx += id % txq_perchan; spin_lock(&ctx->dev->lock_chcr_dev); - ctx->rx_qidx = rxq_idx; - ctx->tx_qidx = txq_idx; + ctx->tx_chan_id = ctx->dev->tx_channel_id; ctx->dev->tx_channel_id = !ctx->dev->tx_channel_id; ctx->dev->rx_channel_id = 0; spin_unlock(&ctx->dev->lock_chcr_dev); + rxq_idx = ctx->tx_chan_id * rxq_perchan; + rxq_idx += id % rxq_perchan; + txq_idx = ctx->tx_chan_id * txq_perchan; + txq_idx += id % txq_perchan; + ctx->rx_qidx = rxq_idx; + ctx->tx_qidx = txq_idx; + /* Channel Id used by SGE to forward packet to Host. + * Same value should be used in cpl_fw6_pld RSS_CH field + * by FW. Driver programs PCI channel ID to be used in fw + * at the time of queue allocation with value "pi->tx_chan" + */ + ctx->pci_chan_id = txq_idx / txq_perchan; } out: return err; @@ -2066,7 +2077,8 @@ static struct sk_buff *create_authenc_wr(struct aead_request *req, sg_param.obsize = req->cryptlen + (op_type ? -authsize : authsize); sg_param.qid = qid; error = map_writesg_phys_cpl(&u_ctx->lldi.pdev->dev, phys_cpl, - reqctx->dst, &sg_param); + reqctx->dst, &sg_param, + ctx->pci_chan_id); if (error) goto dstmap_fail; @@ -2389,7 +2401,7 @@ static struct sk_buff *create_aead_ccm_wr(struct aead_request *req, sg_param.obsize = req->cryptlen + (op_type ? -authsize : authsize); sg_param.qid = qid; error = map_writesg_phys_cpl(&u_ctx->lldi.pdev->dev, phys_cpl, - reqctx->dst, &sg_param); + reqctx->dst, &sg_param, ctx->pci_chan_id); if (error) goto dstmap_fail; @@ -2545,7 +2557,8 @@ static struct sk_buff *create_gcm_wr(struct aead_request *req, sg_param.obsize = req->cryptlen + (op_type ? -authsize : authsize); sg_param.qid = qid; error = map_writesg_phys_cpl(&u_ctx->lldi.pdev->dev, phys_cpl, - reqctx->dst, &sg_param); + reqctx->dst, &sg_param, + ctx->pci_chan_id); if (error) goto dstmap_fail; diff --git a/drivers/crypto/chelsio/chcr_crypto.h b/drivers/crypto/chelsio/chcr_crypto.h index 30af1ee17b876fb0d7d4ceca1327202f4317f67c..e039d9aeb65123a78c68c458de178a57ba95b623 100644 --- a/drivers/crypto/chelsio/chcr_crypto.h +++ b/drivers/crypto/chelsio/chcr_crypto.h @@ -222,6 +222,8 @@ struct chcr_context { struct chcr_dev *dev; unsigned char tx_qidx; unsigned char rx_qidx; + unsigned char tx_chan_id; + unsigned char pci_chan_id; struct __crypto_ctx crypto_ctx[0]; }; diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c index 764be3e6933c856e64875cab50f6ffdc09b522a4..a98a25733a222200d07edf0cbc6805fa2cd69b21 100644 --- a/drivers/crypto/mxs-dcp.c +++ b/drivers/crypto/mxs-dcp.c @@ -63,7 +63,7 @@ struct dcp { struct dcp_coherent_block *coh; struct completion completion[DCP_MAX_CHANS]; - struct mutex mutex[DCP_MAX_CHANS]; + spinlock_t lock[DCP_MAX_CHANS]; struct task_struct *thread[DCP_MAX_CHANS]; struct crypto_queue queue[DCP_MAX_CHANS]; }; @@ -349,13 +349,20 @@ static int dcp_chan_thread_aes(void *data) int ret; - do { - __set_current_state(TASK_INTERRUPTIBLE); + while (!kthread_should_stop()) { + set_current_state(TASK_INTERRUPTIBLE); - mutex_lock(&sdcp->mutex[chan]); + spin_lock(&sdcp->lock[chan]); backlog = crypto_get_backlog(&sdcp->queue[chan]); arq = crypto_dequeue_request(&sdcp->queue[chan]); - mutex_unlock(&sdcp->mutex[chan]); + spin_unlock(&sdcp->lock[chan]); + + if (!backlog && !arq) { + schedule(); + continue; + } + + set_current_state(TASK_RUNNING); if (backlog) backlog->complete(backlog, -EINPROGRESS); @@ -363,11 +370,8 @@ static int dcp_chan_thread_aes(void *data) if (arq) { ret = mxs_dcp_aes_block_crypt(arq); arq->complete(arq, ret); - continue; } - - schedule(); - } while (!kthread_should_stop()); + } return 0; } @@ -409,9 +413,9 @@ static int mxs_dcp_aes_enqueue(struct ablkcipher_request *req, int enc, int ecb) rctx->ecb = ecb; actx->chan = DCP_CHAN_CRYPTO; - mutex_lock(&sdcp->mutex[actx->chan]); + spin_lock(&sdcp->lock[actx->chan]); ret = crypto_enqueue_request(&sdcp->queue[actx->chan], &req->base); - mutex_unlock(&sdcp->mutex[actx->chan]); + spin_unlock(&sdcp->lock[actx->chan]); wake_up_process(sdcp->thread[actx->chan]); @@ -640,13 +644,20 @@ static int dcp_chan_thread_sha(void *data) struct ahash_request *req; int ret, fini; - do { - __set_current_state(TASK_INTERRUPTIBLE); + while (!kthread_should_stop()) { + set_current_state(TASK_INTERRUPTIBLE); - mutex_lock(&sdcp->mutex[chan]); + spin_lock(&sdcp->lock[chan]); backlog = crypto_get_backlog(&sdcp->queue[chan]); arq = crypto_dequeue_request(&sdcp->queue[chan]); - mutex_unlock(&sdcp->mutex[chan]); + spin_unlock(&sdcp->lock[chan]); + + if (!backlog && !arq) { + schedule(); + continue; + } + + set_current_state(TASK_RUNNING); if (backlog) backlog->complete(backlog, -EINPROGRESS); @@ -658,12 +669,8 @@ static int dcp_chan_thread_sha(void *data) ret = dcp_sha_req_to_buf(arq); fini = rctx->fini; arq->complete(arq, ret); - if (!fini) - continue; } - - schedule(); - } while (!kthread_should_stop()); + } return 0; } @@ -721,9 +728,9 @@ static int dcp_sha_update_fx(struct ahash_request *req, int fini) rctx->init = 1; } - mutex_lock(&sdcp->mutex[actx->chan]); + spin_lock(&sdcp->lock[actx->chan]); ret = crypto_enqueue_request(&sdcp->queue[actx->chan], &req->base); - mutex_unlock(&sdcp->mutex[actx->chan]); + spin_unlock(&sdcp->lock[actx->chan]); wake_up_process(sdcp->thread[actx->chan]); mutex_unlock(&actx->mutex); @@ -983,7 +990,7 @@ static int mxs_dcp_probe(struct platform_device *pdev) platform_set_drvdata(pdev, sdcp); for (i = 0; i < DCP_MAX_CHANS; i++) { - mutex_init(&sdcp->mutex[i]); + spin_lock_init(&sdcp->lock[i]); init_completion(&sdcp->completion[i]); crypto_init_queue(&sdcp->queue[i], 50); } diff --git a/drivers/crypto/qat/qat_c3xxx/adf_drv.c b/drivers/crypto/qat/qat_c3xxx/adf_drv.c index f172171668ee90af7f430e9fb0e7aad1137deacd..7c470ae97f60ab63cf020d5cc07f4a1c45b322f6 100644 --- a/drivers/crypto/qat/qat_c3xxx/adf_drv.c +++ b/drivers/crypto/qat/qat_c3xxx/adf_drv.c @@ -123,7 +123,8 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct adf_hw_device_data *hw_data; char name[ADF_DEVICE_NAME_LENGTH]; unsigned int i, bar_nr; - int ret, bar_mask; + unsigned long bar_mask; + int ret; switch (ent->device) { case ADF_C3XXX_PCI_DEVICE_ID: @@ -235,8 +236,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* Find and map all the device's BARS */ i = 0; bar_mask = pci_select_bars(pdev, IORESOURCE_MEM); - for_each_set_bit(bar_nr, (const unsigned long *)&bar_mask, - ADF_PCI_MAX_BARS * 2) { + for_each_set_bit(bar_nr, &bar_mask, ADF_PCI_MAX_BARS * 2) { struct adf_bar *bar = &accel_pci_dev->pci_bars[i++]; bar->base_addr = pci_resource_start(pdev, bar_nr); diff --git a/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c b/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c index 24ec908eb26c25c0f26efbe55b15fc34f421dcf9..613c7d5644ced6d250adefdf3d49a7c4d0876938 100644 --- a/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c +++ b/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c @@ -125,7 +125,8 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct adf_hw_device_data *hw_data; char name[ADF_DEVICE_NAME_LENGTH]; unsigned int i, bar_nr; - int ret, bar_mask; + unsigned long bar_mask; + int ret; switch (ent->device) { case ADF_C3XXXIOV_PCI_DEVICE_ID: @@ -215,8 +216,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* Find and map all the device's BARS */ i = 0; bar_mask = pci_select_bars(pdev, IORESOURCE_MEM); - for_each_set_bit(bar_nr, (const unsigned long *)&bar_mask, - ADF_PCI_MAX_BARS * 2) { + for_each_set_bit(bar_nr, &bar_mask, ADF_PCI_MAX_BARS * 2) { struct adf_bar *bar = &accel_pci_dev->pci_bars[i++]; bar->base_addr = pci_resource_start(pdev, bar_nr); diff --git a/drivers/crypto/qat/qat_c62x/adf_drv.c b/drivers/crypto/qat/qat_c62x/adf_drv.c index 58a984c9c3ec8c54c644294acc9be1203c9ca519..cb11d85d7bb3ded87dac4e186f1fde1f90ba9495 100644 --- a/drivers/crypto/qat/qat_c62x/adf_drv.c +++ b/drivers/crypto/qat/qat_c62x/adf_drv.c @@ -123,7 +123,8 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct adf_hw_device_data *hw_data; char name[ADF_DEVICE_NAME_LENGTH]; unsigned int i, bar_nr; - int ret, bar_mask; + unsigned long bar_mask; + int ret; switch (ent->device) { case ADF_C62X_PCI_DEVICE_ID: @@ -235,8 +236,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* Find and map all the device's BARS */ i = (hw_data->fuses & ADF_DEVICE_FUSECTL_MASK) ? 1 : 0; bar_mask = pci_select_bars(pdev, IORESOURCE_MEM); - for_each_set_bit(bar_nr, (const unsigned long *)&bar_mask, - ADF_PCI_MAX_BARS * 2) { + for_each_set_bit(bar_nr, &bar_mask, ADF_PCI_MAX_BARS * 2) { struct adf_bar *bar = &accel_pci_dev->pci_bars[i++]; bar->base_addr = pci_resource_start(pdev, bar_nr); diff --git a/drivers/crypto/qat/qat_c62xvf/adf_drv.c b/drivers/crypto/qat/qat_c62xvf/adf_drv.c index b9f3e0e4fde97dbbcc81c5614b9c348aecf6f717..278452b8ef81c8a5e5aa296a38bb8caf6402fdd3 100644 --- a/drivers/crypto/qat/qat_c62xvf/adf_drv.c +++ b/drivers/crypto/qat/qat_c62xvf/adf_drv.c @@ -125,7 +125,8 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct adf_hw_device_data *hw_data; char name[ADF_DEVICE_NAME_LENGTH]; unsigned int i, bar_nr; - int ret, bar_mask; + unsigned long bar_mask; + int ret; switch (ent->device) { case ADF_C62XIOV_PCI_DEVICE_ID: @@ -215,8 +216,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* Find and map all the device's BARS */ i = 0; bar_mask = pci_select_bars(pdev, IORESOURCE_MEM); - for_each_set_bit(bar_nr, (const unsigned long *)&bar_mask, - ADF_PCI_MAX_BARS * 2) { + for_each_set_bit(bar_nr, &bar_mask, ADF_PCI_MAX_BARS * 2) { struct adf_bar *bar = &accel_pci_dev->pci_bars[i++]; bar->base_addr = pci_resource_start(pdev, bar_nr); diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_drv.c b/drivers/crypto/qat/qat_dh895xcc/adf_drv.c index 2ce01f010c743513d4a0c1b971638bdf5d72bce7..07b741aed108adafb4f685cf5eca357878a7ca64 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_drv.c +++ b/drivers/crypto/qat/qat_dh895xcc/adf_drv.c @@ -123,7 +123,8 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct adf_hw_device_data *hw_data; char name[ADF_DEVICE_NAME_LENGTH]; unsigned int i, bar_nr; - int ret, bar_mask; + unsigned long bar_mask; + int ret; switch (ent->device) { case ADF_DH895XCC_PCI_DEVICE_ID: @@ -237,8 +238,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* Find and map all the device's BARS */ i = 0; bar_mask = pci_select_bars(pdev, IORESOURCE_MEM); - for_each_set_bit(bar_nr, (const unsigned long *)&bar_mask, - ADF_PCI_MAX_BARS * 2) { + for_each_set_bit(bar_nr, &bar_mask, ADF_PCI_MAX_BARS * 2) { struct adf_bar *bar = &accel_pci_dev->pci_bars[i++]; bar->base_addr = pci_resource_start(pdev, bar_nr); diff --git a/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c b/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c index 26ab17bfc6dabd0fb75d42284f3febef8e390e79..3da0f951cb590a555fea8a9d848c657888a305d9 100644 --- a/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c +++ b/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c @@ -125,7 +125,8 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct adf_hw_device_data *hw_data; char name[ADF_DEVICE_NAME_LENGTH]; unsigned int i, bar_nr; - int ret, bar_mask; + unsigned long bar_mask; + int ret; switch (ent->device) { case ADF_DH895XCCIOV_PCI_DEVICE_ID: @@ -215,8 +216,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* Find and map all the device's BARS */ i = 0; bar_mask = pci_select_bars(pdev, IORESOURCE_MEM); - for_each_set_bit(bar_nr, (const unsigned long *)&bar_mask, - ADF_PCI_MAX_BARS * 2) { + for_each_set_bit(bar_nr, &bar_mask, ADF_PCI_MAX_BARS * 2) { struct adf_bar *bar = &accel_pci_dev->pci_bars[i++]; bar->base_addr = pci_resource_start(pdev, bar_nr); diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c index 08e7bdcaa6e318c5bae2290bf57ac3c1bae3d95e..085c229eab1de06b1eea7e3ac42255419d4a7b42 100644 --- a/drivers/crypto/sahara.c +++ b/drivers/crypto/sahara.c @@ -1351,7 +1351,7 @@ static int sahara_register_algs(struct sahara_dev *dev) err_sha_v3_algs: for (j = 0; j < k; j++) - crypto_unregister_ahash(&sha_v4_algs[j]); + crypto_unregister_ahash(&sha_v3_algs[j]); err_aes_algs: for (j = 0; j < i; j++) @@ -1367,7 +1367,7 @@ static void sahara_unregister_algs(struct sahara_dev *dev) for (i = 0; i < ARRAY_SIZE(aes_algs); i++) crypto_unregister_alg(&aes_algs[i]); - for (i = 0; i < ARRAY_SIZE(sha_v4_algs); i++) + for (i = 0; i < ARRAY_SIZE(sha_v3_algs); i++) crypto_unregister_ahash(&sha_v3_algs[i]); if (dev->version > SAHARA_VERSION_3) diff --git a/drivers/crypto/vmx/aes_cbc.c b/drivers/crypto/vmx/aes_cbc.c index 5285ece4f33a36df39bfd18068dd14ce6a1213db..b71895871be3f1f2ec0b15d19d4087a16f40016f 100644 --- a/drivers/crypto/vmx/aes_cbc.c +++ b/drivers/crypto/vmx/aes_cbc.c @@ -107,24 +107,23 @@ static int p8_aes_cbc_encrypt(struct blkcipher_desc *desc, ret = crypto_skcipher_encrypt(req); skcipher_request_zero(req); } else { - preempt_disable(); - pagefault_disable(); - enable_kernel_vsx(); - blkcipher_walk_init(&walk, dst, src, nbytes); ret = blkcipher_walk_virt(desc, &walk); while ((nbytes = walk.nbytes)) { + preempt_disable(); + pagefault_disable(); + enable_kernel_vsx(); aes_p8_cbc_encrypt(walk.src.virt.addr, walk.dst.virt.addr, nbytes & AES_BLOCK_MASK, &ctx->enc_key, walk.iv, 1); + disable_kernel_vsx(); + pagefault_enable(); + preempt_enable(); + nbytes &= AES_BLOCK_SIZE - 1; ret = blkcipher_walk_done(desc, &walk, nbytes); } - - disable_kernel_vsx(); - pagefault_enable(); - preempt_enable(); } return ret; @@ -147,24 +146,23 @@ static int p8_aes_cbc_decrypt(struct blkcipher_desc *desc, ret = crypto_skcipher_decrypt(req); skcipher_request_zero(req); } else { - preempt_disable(); - pagefault_disable(); - enable_kernel_vsx(); - blkcipher_walk_init(&walk, dst, src, nbytes); ret = blkcipher_walk_virt(desc, &walk); while ((nbytes = walk.nbytes)) { + preempt_disable(); + pagefault_disable(); + enable_kernel_vsx(); aes_p8_cbc_encrypt(walk.src.virt.addr, walk.dst.virt.addr, nbytes & AES_BLOCK_MASK, &ctx->dec_key, walk.iv, 0); + disable_kernel_vsx(); + pagefault_enable(); + preempt_enable(); + nbytes &= AES_BLOCK_SIZE - 1; ret = blkcipher_walk_done(desc, &walk, nbytes); } - - disable_kernel_vsx(); - pagefault_enable(); - preempt_enable(); } return ret; diff --git a/drivers/crypto/vmx/aes_ctr.c b/drivers/crypto/vmx/aes_ctr.c index 02ba5f2aa0e6e8d09b431d9ad0019fa4c1549f94..cd777c75291dfb72f6df5c2967909da694627b78 100644 --- a/drivers/crypto/vmx/aes_ctr.c +++ b/drivers/crypto/vmx/aes_ctr.c @@ -27,21 +27,23 @@ #include #include #include +#include + #include "aesp8-ppc.h" struct p8_aes_ctr_ctx { - struct crypto_blkcipher *fallback; + struct crypto_skcipher *fallback; struct aes_key enc_key; }; static int p8_aes_ctr_init(struct crypto_tfm *tfm) { const char *alg = crypto_tfm_alg_name(tfm); - struct crypto_blkcipher *fallback; + struct crypto_skcipher *fallback; struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx(tfm); - fallback = - crypto_alloc_blkcipher(alg, 0, CRYPTO_ALG_NEED_FALLBACK); + fallback = crypto_alloc_skcipher(alg, 0, + CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); if (IS_ERR(fallback)) { printk(KERN_ERR "Failed to allocate transformation for '%s': %ld\n", @@ -49,9 +51,9 @@ static int p8_aes_ctr_init(struct crypto_tfm *tfm) return PTR_ERR(fallback); } - crypto_blkcipher_set_flags( + crypto_skcipher_set_flags( fallback, - crypto_blkcipher_get_flags((struct crypto_blkcipher *)tfm)); + crypto_skcipher_get_flags((struct crypto_skcipher *)tfm)); ctx->fallback = fallback; return 0; @@ -62,7 +64,7 @@ static void p8_aes_ctr_exit(struct crypto_tfm *tfm) struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx(tfm); if (ctx->fallback) { - crypto_free_blkcipher(ctx->fallback); + crypto_free_skcipher(ctx->fallback); ctx->fallback = NULL; } } @@ -81,7 +83,7 @@ static int p8_aes_ctr_setkey(struct crypto_tfm *tfm, const u8 *key, pagefault_enable(); preempt_enable(); - ret += crypto_blkcipher_setkey(ctx->fallback, key, keylen); + ret += crypto_skcipher_setkey(ctx->fallback, key, keylen); return ret; } @@ -115,15 +117,14 @@ static int p8_aes_ctr_crypt(struct blkcipher_desc *desc, struct blkcipher_walk walk; struct p8_aes_ctr_ctx *ctx = crypto_tfm_ctx(crypto_blkcipher_tfm(desc->tfm)); - struct blkcipher_desc fallback_desc = { - .tfm = ctx->fallback, - .info = desc->info, - .flags = desc->flags - }; if (in_interrupt()) { - ret = crypto_blkcipher_encrypt(&fallback_desc, dst, src, - nbytes); + SKCIPHER_REQUEST_ON_STACK(req, ctx->fallback); + skcipher_request_set_tfm(req, ctx->fallback); + skcipher_request_set_callback(req, desc->flags, NULL, NULL); + skcipher_request_set_crypt(req, src, dst, nbytes, desc->info); + ret = crypto_skcipher_encrypt(req); + skcipher_request_zero(req); } else { blkcipher_walk_init(&walk, dst, src, nbytes); ret = blkcipher_walk_virt_block(desc, &walk, AES_BLOCK_SIZE); diff --git a/drivers/crypto/vmx/aes_xts.c b/drivers/crypto/vmx/aes_xts.c index 8bd9aff0f55fba6639b67147cf97c2fcfce12bfc..e9954a7d46944d36cd2aeffdfd8202b54c793d71 100644 --- a/drivers/crypto/vmx/aes_xts.c +++ b/drivers/crypto/vmx/aes_xts.c @@ -116,32 +116,39 @@ static int p8_aes_xts_crypt(struct blkcipher_desc *desc, ret = enc? crypto_skcipher_encrypt(req) : crypto_skcipher_decrypt(req); skcipher_request_zero(req); } else { + blkcipher_walk_init(&walk, dst, src, nbytes); + + ret = blkcipher_walk_virt(desc, &walk); + preempt_disable(); pagefault_disable(); enable_kernel_vsx(); - blkcipher_walk_init(&walk, dst, src, nbytes); - - ret = blkcipher_walk_virt(desc, &walk); iv = walk.iv; memset(tweak, 0, AES_BLOCK_SIZE); aes_p8_encrypt(iv, tweak, &ctx->tweak_key); + disable_kernel_vsx(); + pagefault_enable(); + preempt_enable(); + while ((nbytes = walk.nbytes)) { + preempt_disable(); + pagefault_disable(); + enable_kernel_vsx(); if (enc) aes_p8_xts_encrypt(walk.src.virt.addr, walk.dst.virt.addr, nbytes & AES_BLOCK_MASK, &ctx->enc_key, NULL, tweak); else aes_p8_xts_decrypt(walk.src.virt.addr, walk.dst.virt.addr, nbytes & AES_BLOCK_MASK, &ctx->dec_key, NULL, tweak); + disable_kernel_vsx(); + pagefault_enable(); + preempt_enable(); nbytes &= AES_BLOCK_SIZE - 1; ret = blkcipher_walk_done(desc, &walk, nbytes); } - - disable_kernel_vsx(); - pagefault_enable(); - preempt_enable(); } return ret; } diff --git a/drivers/dax/device.c b/drivers/dax/device.c index 7b0bf825c4e73c588ff93183cf5315665d69e082..050e299129acf5167774fbd9d6569feabd58f685 100644 --- a/drivers/dax/device.c +++ b/drivers/dax/device.c @@ -188,14 +188,16 @@ static int check_vma(struct dev_dax *dev_dax, struct vm_area_struct *vma, /* prevent private mappings from being established */ if ((vma->vm_flags & VM_MAYSHARE) != VM_MAYSHARE) { - dev_info(dev, "%s: %s: fail, attempted private mapping\n", + dev_info_ratelimited(dev, + "%s: %s: fail, attempted private mapping\n", current->comm, func); return -EINVAL; } mask = dax_region->align - 1; if (vma->vm_start & mask || vma->vm_end & mask) { - dev_info(dev, "%s: %s: fail, unaligned vma (%#lx - %#lx, %#lx)\n", + dev_info_ratelimited(dev, + "%s: %s: fail, unaligned vma (%#lx - %#lx, %#lx)\n", current->comm, func, vma->vm_start, vma->vm_end, mask); return -EINVAL; @@ -203,13 +205,15 @@ static int check_vma(struct dev_dax *dev_dax, struct vm_area_struct *vma, if ((dax_region->pfn_flags & (PFN_DEV|PFN_MAP)) == PFN_DEV && (vma->vm_flags & VM_DONTCOPY) == 0) { - dev_info(dev, "%s: %s: fail, dax range requires MADV_DONTFORK\n", + dev_info_ratelimited(dev, + "%s: %s: fail, dax range requires MADV_DONTFORK\n", current->comm, func); return -EINVAL; } if (!vma_is_dax(vma)) { - dev_info(dev, "%s: %s: fail, vma is not DAX capable\n", + dev_info_ratelimited(dev, + "%s: %s: fail, vma is not DAX capable\n", current->comm, func); return -EINVAL; } diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index c5666c870b335df3cd6320e99ecac1bf478c50ee..af34cfcaf49e2c0a98018417ced862940fa5b05f 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -522,7 +522,7 @@ static void devfreq_dev_release(struct device *dev) devfreq->profile->exit(devfreq->dev.parent); mutex_destroy(&devfreq->lock); - mutex_destroy(&devfreq->sysfs_lock); + mutex_destroy(&devfreq->event_lock); kfree(devfreq); } @@ -565,7 +565,7 @@ struct devfreq *devfreq_add_device(struct device *dev, } mutex_init(&devfreq->lock); - mutex_init(&devfreq->sysfs_lock); + mutex_init(&devfreq->event_lock); mutex_lock(&devfreq->lock); devfreq->dev.parent = dev; devfreq->dev.class = devfreq_class; @@ -576,6 +576,7 @@ struct devfreq *devfreq_add_device(struct device *dev, devfreq->last_status.current_frequency = profile->initial_freq; devfreq->data = data; devfreq->nb.notifier_call = devfreq_notifier_call; + devfreq->dev_suspended = false; if (!devfreq->profile->max_state && !devfreq->profile->freq_table) { mutex_unlock(&devfreq->lock); @@ -777,14 +778,23 @@ EXPORT_SYMBOL(devm_devfreq_remove_device); */ int devfreq_suspend_device(struct devfreq *devfreq) { + int ret; + if (!devfreq) return -EINVAL; - if (!devfreq->governor) + mutex_lock(&devfreq->event_lock); + if (!devfreq->governor || devfreq->dev_suspended) { + mutex_unlock(&devfreq->event_lock); return 0; + } - return devfreq->governor->event_handler(devfreq, + ret = devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_SUSPEND, NULL); + if (!ret) + devfreq->dev_suspended = true; + mutex_unlock(&devfreq->event_lock); + return ret; } EXPORT_SYMBOL(devfreq_suspend_device); @@ -798,14 +808,22 @@ EXPORT_SYMBOL(devfreq_suspend_device); */ int devfreq_resume_device(struct devfreq *devfreq) { + int ret; if (!devfreq) return -EINVAL; - if (!devfreq->governor) + mutex_lock(&devfreq->event_lock); + if (!devfreq->governor) { + mutex_unlock(&devfreq->event_lock); return 0; + } - return devfreq->governor->event_handler(devfreq, + ret = devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_RESUME, NULL); + if (!ret) + devfreq->dev_suspended = false; + mutex_unlock(&devfreq->event_lock); + return ret; } EXPORT_SYMBOL(devfreq_resume_device); @@ -965,7 +983,11 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr, goto out; } - mutex_lock(&df->sysfs_lock); + mutex_lock(&df->event_lock); + if (df->dev_suspended) { + ret = -EINVAL; + goto gov_stop_out; + } if (df->governor) { ret = df->governor->event_handler(df, DEVFREQ_GOV_STOP, NULL); if (ret) { @@ -991,7 +1013,7 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr, } gov_stop_out: - mutex_unlock(&df->sysfs_lock); + mutex_unlock(&df->event_lock); out: mutex_unlock(&devfreq_list_lock); @@ -1086,10 +1108,10 @@ static ssize_t polling_interval_store(struct device *dev, if (ret != 1) return -EINVAL; - mutex_lock(&df->sysfs_lock); + mutex_lock(&df->event_lock); df->governor->event_handler(df, DEVFREQ_GOV_INTERVAL, &value); ret = count; - mutex_unlock(&df->sysfs_lock); + mutex_unlock(&df->event_lock); return ret; } @@ -1107,7 +1129,7 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr, if (ret != 1) return -EINVAL; - mutex_lock(&df->sysfs_lock); + mutex_lock(&df->event_lock); mutex_lock(&df->lock); max = df->max_freq; if (value && max && value > max) { @@ -1120,7 +1142,7 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr, ret = count; unlock: mutex_unlock(&df->lock); - mutex_unlock(&df->sysfs_lock); + mutex_unlock(&df->event_lock); return ret; } @@ -1136,7 +1158,7 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr, if (ret != 1) return -EINVAL; - mutex_lock(&df->sysfs_lock); + mutex_lock(&df->event_lock); mutex_lock(&df->lock); min = df->min_freq; if (value && min && value < min) { @@ -1149,7 +1171,7 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr, ret = count; unlock: mutex_unlock(&df->lock); - mutex_unlock(&df->sysfs_lock); + mutex_unlock(&df->event_lock); return ret; } diff --git a/drivers/devfreq/governor_gpubw_mon.c b/drivers/devfreq/governor_gpubw_mon.c index 9c24eef6a4976d049aa126ffde5a1ab172789c25..6c53704aac9c3d633e7ae58fc5e158f48e1dc1d5 100644 --- a/drivers/devfreq/governor_gpubw_mon.c +++ b/drivers/devfreq/governor_gpubw_mon.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -24,6 +24,7 @@ #define HIST 5 #define TARGET 80 #define CAP 75 +#define WAIT_THRESHOLD 10 /* AB vote is in multiple of BW_STEP Mega bytes */ #define BW_STEP 160 @@ -65,7 +66,9 @@ static int devfreq_gpubw_get_target(struct devfreq *df, int result; int level = 0; int act_level; + int norm_max_cycles; int norm_cycles; + int wait_active_percent; int gpu_percent; /* * Normalized AB should at max usage be the gpu_bimc frequency in MHz. @@ -94,8 +97,12 @@ static int devfreq_gpubw_get_target(struct devfreq *df, if (priv->bus.total_time < LONG_FLOOR) return result; + norm_max_cycles = (unsigned int)(priv->bus.ram_time) / + (unsigned int) priv->bus.total_time; norm_cycles = (unsigned int)(priv->bus.ram_time + priv->bus.ram_wait) / (unsigned int) priv->bus.total_time; + wait_active_percent = (100 * (unsigned int)priv->bus.ram_wait) / + (unsigned int) priv->bus.ram_time; gpu_percent = (100 * (unsigned int)priv->bus.gpu_time) / (unsigned int) priv->bus.total_time; @@ -104,8 +111,8 @@ static int devfreq_gpubw_get_target(struct devfreq *df, * FAST hint. Otherwise check the current value against the current * cutoffs. */ - if (norm_cycles > priv->bus.max) { - _update_cutoff(priv, norm_cycles); + if (norm_max_cycles > priv->bus.max) { + _update_cutoff(priv, norm_max_cycles); bus_profile->flag = DEVFREQ_FLAG_FAST_HINT; } else { /* GPU votes for IB not AB so don't under vote the system */ @@ -114,7 +121,8 @@ static int devfreq_gpubw_get_target(struct devfreq *df, act_level = (act_level < 0) ? 0 : act_level; act_level = (act_level >= priv->bus.num) ? (priv->bus.num - 1) : act_level; - if (norm_cycles > priv->bus.up[act_level] && + if ((norm_cycles > priv->bus.up[act_level] || + wait_active_percent > WAIT_THRESHOLD) && gpu_percent > CAP) bus_profile->flag = DEVFREQ_FLAG_FAST_HINT; else if (norm_cycles < priv->bus.down[act_level] && level) diff --git a/drivers/devfreq/governor_memlat.c b/drivers/devfreq/governor_memlat.c index 184f33f0ef18b7306944db556a3c640b1dbb5e3e..409154e770f2cacab8ba0a16e43134dd32da5684 100644 --- a/drivers/devfreq/governor_memlat.c +++ b/drivers/devfreq/governor_memlat.c @@ -323,7 +323,7 @@ static int devfreq_memlat_get_freq(struct devfreq *df, return 0; } -gov_attr(ratio_ceil, 1U, 10000U); +gov_attr(ratio_ceil, 1U, 20000U); gov_attr(stall_floor, 0U, 100U); static struct attribute *memlat_dev_attr[] = { diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig index ed3b785bae37e1cd589697f04d1b868dc2fccd9b..dbaa78b3ae89ec6137614c1cfd7eeca675c3a65b 100644 --- a/drivers/dma-buf/Kconfig +++ b/drivers/dma-buf/Kconfig @@ -30,4 +30,15 @@ config SW_SYNC WARNING: improper use of this can result in deadlocking kernel drivers from userspace. Intended for test and debug only. +config DEBUG_DMA_BUF_REF + bool "DEBUG Reference Count" + depends on STACKDEPOT + depends on DMA_SHARED_BUFFER + default n + ---help--- + Save stack traces for every call to dma_buf_get and dma_buf_put, to + help debug memory leaks. Potential leaks may be found by manually + matching the get/put call stacks. This feature consumes extra memory + in order to save the stack traces using STACKDEPOT. + endmenu diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile index c33bf88631479411549ab38cb96d748784e3f74c..dcbc33fb4db09cb4fea923ae9f7d54374e46b848 100644 --- a/drivers/dma-buf/Makefile +++ b/drivers/dma-buf/Makefile @@ -1,3 +1,4 @@ obj-y := dma-buf.o dma-fence.o dma-fence-array.o reservation.o seqno-fence.o obj-$(CONFIG_SYNC_FILE) += sync_file.o obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o +obj-$(CONFIG_DEBUG_DMA_BUF_REF) += dma-buf-ref.o diff --git a/drivers/dma-buf/dma-buf-ref.c b/drivers/dma-buf/dma-buf-ref.c new file mode 100644 index 0000000000000000000000000000000000000000..76047104faca4a49e46d66202ff048d1a99024f7 --- /dev/null +++ b/drivers/dma-buf/dma-buf-ref.c @@ -0,0 +1,123 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include + +#define DMA_BUF_STACK_DEPTH (16) + +struct dma_buf_ref { + struct list_head list; + depot_stack_handle_t handle; + int count; +}; + +void dma_buf_ref_init(struct dma_buf *dmabuf) +{ + INIT_LIST_HEAD(&dmabuf->refs); +} + +void dma_buf_ref_destroy(struct dma_buf *dmabuf) +{ + struct dma_buf_ref *r, *n; + + mutex_lock(&dmabuf->lock); + list_for_each_entry_safe(r, n, &dmabuf->refs, list) { + list_del(&r->list); + kfree(r); + } + mutex_unlock(&dmabuf->lock); +} + +static void dma_buf_ref_insert_handle(struct dma_buf *dmabuf, + depot_stack_handle_t handle, + int count) +{ + struct dma_buf_ref *r; + + mutex_lock(&dmabuf->lock); + list_for_each_entry(r, &dmabuf->refs, list) { + if (r->handle == handle) { + r->count += count; + goto out; + } + } + + r = kzalloc(sizeof(*r), GFP_KERNEL); + if (!r) + goto out; + + INIT_LIST_HEAD(&r->list); + r->handle = handle; + r->count = count; + list_add(&r->list, &dmabuf->refs); + +out: + mutex_unlock(&dmabuf->lock); +} + +void dma_buf_ref_mod(struct dma_buf *dmabuf, int nr) +{ + unsigned long entries[DMA_BUF_STACK_DEPTH]; + struct stack_trace trace = { + .nr_entries = 0, + .entries = entries, + .max_entries = DMA_BUF_STACK_DEPTH, + .skip = 1 + }; + depot_stack_handle_t handle; + + save_stack_trace(&trace); + if (trace.nr_entries != 0 && + trace.entries[trace.nr_entries-1] == ULONG_MAX) + trace.nr_entries--; + + handle = depot_save_stack(&trace, GFP_KERNEL); + if (!handle) + return; + + dma_buf_ref_insert_handle(dmabuf, handle, nr); +} + +/** + * Called with dmabuf->lock held + */ +int dma_buf_ref_show(struct seq_file *s, struct dma_buf *dmabuf) +{ + char *buf; + struct dma_buf_ref *ref; + int count = 0; + struct stack_trace trace; + + buf = (void *)__get_free_page(GFP_KERNEL); + if (!buf) + return -ENOMEM; + + list_for_each_entry(ref, &dmabuf->refs, list) { + count += ref->count; + + seq_printf(s, "References: %d\n", ref->count); + depot_fetch_stack(ref->handle, &trace); + snprint_stack_trace(buf, PAGE_SIZE, &trace, 0); + seq_puts(s, buf); + seq_putc(s, '\n'); + } + + seq_printf(s, "Total references: %d\n\n\n", count); + free_page((unsigned long)buf); + + return 0; +} diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index a0e33a7d8f94b35834df01f5f2c5c0f6248b55c9..c7eadb3efe6daa1605f4ff9987752e8819ff56d6 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -93,6 +93,8 @@ static int dma_buf_release(struct inode *inode, struct file *file) list_del(&dmabuf->list_node); mutex_unlock(&db_list.lock); + dma_buf_ref_destroy(dmabuf); + if (dmabuf->resv == (struct reservation_object *)&dmabuf[1]) reservation_object_fini(dmabuf->resv); @@ -495,6 +497,9 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) mutex_init(&dmabuf->lock); INIT_LIST_HEAD(&dmabuf->attachments); + dma_buf_ref_init(dmabuf); + dma_buf_ref_mod(dmabuf, 1); + mutex_lock(&db_list.lock); list_add(&dmabuf->list_node, &db_list.head); mutex_unlock(&db_list.lock); @@ -556,6 +561,7 @@ struct dma_buf *dma_buf_get(int fd) fput(file); return ERR_PTR(-EINVAL); } + dma_buf_ref_mod(file->private_data, 1); return file->private_data; } @@ -576,6 +582,7 @@ void dma_buf_put(struct dma_buf *dmabuf) if (WARN_ON(!dmabuf || !dmabuf->file)) return; + dma_buf_ref_mod(dmabuf, -1); fput(dmabuf->file); } EXPORT_SYMBOL_GPL(dma_buf_put); @@ -1266,6 +1273,8 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused) seq_printf(s, "Total %d devices attached\n\n", attach_count); + dma_buf_ref_show(s, buf_obj); + count++; size += buf_obj->size; mutex_unlock(&buf_obj->lock); diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c index 01d2a750a6217c062daedbac6b44d0e59aafd2e2..219ae3b545dbab035d20ce628c7a025159f9e9bb 100644 --- a/drivers/dma/k3dma.c +++ b/drivers/dma/k3dma.c @@ -787,7 +787,7 @@ static struct dma_chan *k3_of_dma_simple_xlate(struct of_phandle_args *dma_spec, struct k3_dma_dev *d = ofdma->of_dma_data; unsigned int request = dma_spec->args[0]; - if (request > d->dma_requests) + if (request >= d->dma_requests) return NULL; return dma_get_slave_channel(&(d->chans[request].vc.chan)); diff --git a/drivers/dma/mv_xor_v2.c b/drivers/dma/mv_xor_v2.c index 3548caa9e9339f17208a62066ad055c842491e3b..75eef589d0ecbe717392df0e0a9ab352e24bdea9 100644 --- a/drivers/dma/mv_xor_v2.c +++ b/drivers/dma/mv_xor_v2.c @@ -898,6 +898,8 @@ static int mv_xor_v2_remove(struct platform_device *pdev) platform_msi_domain_free_irqs(&pdev->dev); + tasklet_kill(&xor_dev->irq_tasklet); + clk_disable_unprepare(xor_dev->clk); return 0; diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 7432c8894e321c415bb3f6d18a3ff73e3b181e04..6afd42cfbf5d5014c069b1e750b741dc1dc9c31d 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -2142,13 +2142,14 @@ static int pl330_terminate_all(struct dma_chan *chan) pm_runtime_get_sync(pl330->ddma.dev); spin_lock_irqsave(&pch->lock, flags); + spin_lock(&pl330->lock); _stop(pch->thread); - spin_unlock(&pl330->lock); - pch->thread->req[0].desc = NULL; pch->thread->req[1].desc = NULL; pch->thread->req_running = -1; + spin_unlock(&pl330->lock); + power_down = pch->active; pch->active = false; @@ -2923,7 +2924,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) pd->src_addr_widths = PL330_DMA_BUSWIDTHS; pd->dst_addr_widths = PL330_DMA_BUSWIDTHS; pd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); - pd->residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT; + pd->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; pd->max_burst = ((pl330->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP) ? 1 : PL330_MAX_BURST); diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 480072139b7aa00db3d27d9381c0e6eace04835e..80801c616395e144def7675192625a4dcf5788cf 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -215,6 +215,7 @@ const char * const edac_mem_types[] = { [MEM_LRDDR3] = "Load-Reduced DDR3 RAM", [MEM_DDR4] = "Unbuffered DDR4 RAM", [MEM_RDDR4] = "Registered DDR4 RAM", + [MEM_LRDDR4] = "Load-Reduced-DDR4-RAM", }; EXPORT_SYMBOL_GPL(edac_mem_types); diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index c70ea82c815c90966e1cf22c3781d16f5eed6ce6..594ce6abd370085203184b038c690d1954373872 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -1097,14 +1097,14 @@ int __init edac_mc_sysfs_init(void) err = device_add(mci_pdev); if (err < 0) - goto out_dev_free; + goto out_put_device; edac_dbg(0, "device %s created\n", dev_name(mci_pdev)); return 0; - out_dev_free: - kfree(mci_pdev); + out_put_device: + put_device(mci_pdev); out: return err; } diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index c16c3b931b3d0ef9cd68b01e6d81de4987d5c794..6c7d5f20eacbd8c9652561f7edc1bebb801e6d73 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1177,15 +1177,14 @@ static int i7core_create_sysfs_devices(struct mem_ctl_info *mci) rc = device_add(pvt->addrmatch_dev); if (rc < 0) - return rc; + goto err_put_addrmatch; if (!pvt->is_registered) { pvt->chancounts_dev = kzalloc(sizeof(*pvt->chancounts_dev), GFP_KERNEL); if (!pvt->chancounts_dev) { - put_device(pvt->addrmatch_dev); - device_del(pvt->addrmatch_dev); - return -ENOMEM; + rc = -ENOMEM; + goto err_del_addrmatch; } pvt->chancounts_dev->type = &all_channel_counts_type; @@ -1199,9 +1198,18 @@ static int i7core_create_sysfs_devices(struct mem_ctl_info *mci) rc = device_add(pvt->chancounts_dev); if (rc < 0) - return rc; + goto err_put_chancounts; } return 0; + +err_put_chancounts: + put_device(pvt->chancounts_dev); +err_del_addrmatch: + device_del(pvt->addrmatch_dev); +err_put_addrmatch: + put_device(pvt->addrmatch_dev); + + return rc; } static void i7core_delete_sysfs_devices(struct mem_ctl_info *mci) @@ -1211,11 +1219,11 @@ static void i7core_delete_sysfs_devices(struct mem_ctl_info *mci) edac_dbg(1, "\n"); if (!pvt->is_registered) { - put_device(pvt->chancounts_dev); device_del(pvt->chancounts_dev); + put_device(pvt->chancounts_dev); } - put_device(pvt->addrmatch_dev); device_del(pvt->addrmatch_dev); + put_device(pvt->addrmatch_dev); } /**************************************************************************** diff --git a/drivers/esoc/esoc-mdm-4x.c b/drivers/esoc/esoc-mdm-4x.c index bfa0658ea61603093ba0e0285b9d78397a656a3b..2ff2972d454bbae57eaf4e5a2c4ee7afc35142f2 100644 --- a/drivers/esoc/esoc-mdm-4x.c +++ b/drivers/esoc/esoc-mdm-4x.c @@ -1051,6 +1051,26 @@ static int sdx50m_setup_hw(struct mdm_ctrl *mdm, return ret; } +static int sdxprairie_setup_hw(struct mdm_ctrl *mdm, + const struct mdm_ops *ops, + struct platform_device *pdev) +{ + int ret; + + /* Same configuration as that of sdx50, except for the name */ + ret = sdx50m_setup_hw(mdm, ops, pdev); + if (ret) { + dev_err(mdm->dev, "Hardware setup failed for sdxprairie\n"); + esoc_mdm_log("Hardware setup failed for sdxprairie\n"); + return ret; + } + + mdm->esoc->name = SDXPRAIRIE_LABEL; + esoc_mdm_log("Hardware setup done for sdxprairie\n"); + + return ret; +} + static struct esoc_clink_ops mdm_cops = { .cmd_exe = mdm_cmd_exe, .get_status = mdm_get_status, @@ -1070,11 +1090,19 @@ static struct mdm_ops sdx50m_ops = { .pon_ops = &sdx50m_pon_ops, }; +static struct mdm_ops sdxprairie_ops = { + .clink_ops = &mdm_cops, + .config_hw = sdxprairie_setup_hw, + .pon_ops = &sdx50m_pon_ops, +}; + static const struct of_device_id mdm_dt_match[] = { { .compatible = "qcom,ext-mdm9x55", .data = &mdm9x55_ops, }, { .compatible = "qcom,ext-sdx50m", .data = &sdx50m_ops, }, + { .compatible = "qcom,ext-sdxprairie", + .data = &sdxprairie_ops, }, {}, }; MODULE_DEVICE_TABLE(of, mdm_dt_match); diff --git a/drivers/esoc/esoc-mdm-drv.c b/drivers/esoc/esoc-mdm-drv.c index aef3a8b81ae25216eb033ada2f460855892bcf3b..6b343fa57846a6832707a7cc2e1f094be29cfc68 100644 --- a/drivers/esoc/esoc-mdm-drv.c +++ b/drivers/esoc/esoc-mdm-drv.c @@ -68,9 +68,13 @@ struct mdm_drv { struct workqueue_struct *mdm_queue; struct work_struct ssr_work; struct notifier_block esoc_restart; + struct mutex poff_lock; }; #define to_mdm_drv(d) container_of(d, struct mdm_drv, cmd_eng) +static void esoc_client_link_power_off(struct esoc_clink *esoc_clink, + bool mdm_crashed); + static int esoc_msm_restart_handler(struct notifier_block *nb, unsigned long action, void *data) { @@ -82,10 +86,20 @@ static int esoc_msm_restart_handler(struct notifier_block *nb, if (action == SYS_RESTART) { if (mdm_dbg_stall_notify(ESOC_PRIMARY_REBOOT)) return NOTIFY_OK; + mutex_lock(&mdm_drv->poff_lock); + if (mdm_drv->mode == PWR_OFF) { + esoc_mdm_log( + "Reboot notifier: mdm already powered-off\n"); + mutex_unlock(&mdm_drv->poff_lock); + return NOTIFY_OK; + } + esoc_client_link_power_off(esoc_clink, false); esoc_mdm_log( "Reboot notifier: Notifying esoc of cold reboot\n"); dev_dbg(&esoc_clink->dev, "Notifying esoc of cold reboot\n"); clink_ops->notify(ESOC_PRIMARY_REBOOT, esoc_clink); + mdm_drv->mode = PWR_OFF; + mutex_unlock(&mdm_drv->poff_lock); } return NOTIFY_OK; } @@ -250,18 +264,26 @@ static int mdm_subsys_shutdown(const struct subsys_desc *crashed_subsys, mdm_drv->mode = IN_DEBUG; } else if (!force_stop) { esoc_mdm_log("Graceful shutdown mode\n"); + mutex_lock(&mdm_drv->poff_lock); + if (mdm_drv->mode == PWR_OFF) { + mutex_unlock(&mdm_drv->poff_lock); + esoc_mdm_log("mdm already powered-off\n"); + return 0; + } if (esoc_clink->subsys.sysmon_shutdown_ret) { esoc_mdm_log( "Executing the ESOC_FORCE_PWR_OFF command\n"); ret = clink_ops->cmd_exe(ESOC_FORCE_PWR_OFF, esoc_clink); } else { - if (mdm_dbg_stall_cmd(ESOC_PWR_OFF)) + if (mdm_dbg_stall_cmd(ESOC_PWR_OFF)) { /* Since power off command is masked * we return success, and leave the state * of the command engine as is. */ + mutex_unlock(&mdm_drv->poff_lock); return 0; + } dev_dbg(&esoc_clink->dev, "Sending sysmon-shutdown\n"); esoc_mdm_log("Executing the ESOC_PWR_OFF command\n"); ret = clink_ops->cmd_exe(ESOC_PWR_OFF, esoc_clink); @@ -270,12 +292,14 @@ static int mdm_subsys_shutdown(const struct subsys_desc *crashed_subsys, esoc_mdm_log( "Executing the ESOC_PWR_OFF command failed\n"); dev_err(&esoc_clink->dev, "failed to exe power off\n"); + mutex_unlock(&mdm_drv->poff_lock); return ret; } esoc_client_link_power_off(esoc_clink, false); /* Pull the reset line low to turn off the device */ clink_ops->cmd_exe(ESOC_FORCE_PWR_OFF, esoc_clink); mdm_drv->mode = PWR_OFF; + mutex_unlock(&mdm_drv->poff_lock); } esoc_mdm_log("Shutdown completed\n"); return 0; @@ -473,6 +497,7 @@ int esoc_ssr_probe(struct esoc_clink *esoc_clink, struct esoc_drv *drv) dev_err(&esoc_clink->dev, "failed to register cmd engine\n"); return ret; } + mutex_init(&mdm_drv->poff_lock); ret = mdm_register_ssr(esoc_clink); if (ret) goto ssr_err; @@ -518,6 +543,10 @@ static struct esoc_compat compat_table[] = { .name = "SDX50M", .data = NULL, }, + { + .name = "SDXPRAIRIE", + .data = NULL, + }, }; static struct esoc_drv esoc_ssr_drv = { diff --git a/drivers/esoc/esoc-mdm.h b/drivers/esoc/esoc-mdm.h index b6e1965b6889a9c8209034709cb4338e6649ad34..107fad66b1a330a94a1d152177d18107fb76bf40 100644 --- a/drivers/esoc/esoc-mdm.h +++ b/drivers/esoc/esoc-mdm.h @@ -31,6 +31,7 @@ #define MDM9x55_PCIE "PCIe" #define SDX50M_LABEL "SDX50M" #define SDX50M_PCIE "PCIe" +#define SDXPRAIRIE_LABEL "SDXPRAIRIE" #define MDM2AP_STATUS_TIMEOUT_MS 120000L #define MDM_MODEM_TIMEOUT 3000 #define DEF_RAMDUMP_TIMEOUT 120000 diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index e098d7a7138a595e643a70817ff84408e9075d51..97bd841334e40e5aabf3ed136b54eaac9ce753cc 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -433,8 +433,8 @@ int extcon_sync(struct extcon_dev *edev, unsigned int id) return index; spin_lock_irqsave(&edev->lock, flags); - state = !!(edev->state & BIT(index)); + spin_unlock_irqrestore(&edev->lock, flags); /* * Call functions in a raw notifier chain for the specific one @@ -448,6 +448,7 @@ int extcon_sync(struct extcon_dev *edev, unsigned int id) */ raw_notifier_call_chain(&edev->nh_all, state, edev); + spin_lock_irqsave(&edev->lock, flags); /* This could be in interrupt handler */ prop_buf = (char *)get_zeroed_page(GFP_ATOMIC); if (!prop_buf) { diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c index 80d1a885def5c2dd8bd15591bcc7c62d9b2e3b8c..a7c522eac640feb84d25b436cf54461e797f8d10 100644 --- a/drivers/firmware/efi/arm-init.c +++ b/drivers/firmware/efi/arm-init.c @@ -259,7 +259,6 @@ void __init efi_init(void) reserve_regions(); efi_esrt_init(); - efi_memmap_unmap(); memblock_reserve(params.mmap & PAGE_MASK, PAGE_ALIGN(params.mmap_size + diff --git a/drivers/firmware/efi/arm-runtime.c b/drivers/firmware/efi/arm-runtime.c index 86a1ad17a32e2cd4acf3fb64a774b7cfabc271f1..8995a48bd0676229f5d22396d75a2946fed5b721 100644 --- a/drivers/firmware/efi/arm-runtime.c +++ b/drivers/firmware/efi/arm-runtime.c @@ -122,11 +122,13 @@ static int __init arm_enable_runtime_services(void) { u64 mapsize; - if (!efi_enabled(EFI_BOOT)) { + if (!efi_enabled(EFI_BOOT) || !efi_enabled(EFI_MEMMAP)) { pr_info("EFI services will not be available.\n"); return 0; } + efi_memmap_unmap(); + if (efi_runtime_disabled()) { pr_info("EFI runtime services will be disabled.\n"); return 0; diff --git a/drivers/firmware/efi/esrt.c b/drivers/firmware/efi/esrt.c index c47e0c6ec00f858c0b9960f605974b4f2e4b1294..f3c28777b8c6fed9bb351ad1d93307b3651a8adb 100644 --- a/drivers/firmware/efi/esrt.c +++ b/drivers/firmware/efi/esrt.c @@ -333,7 +333,8 @@ void __init efi_esrt_init(void) end = esrt_data + size; pr_info("Reserving ESRT space from %pa to %pa.\n", &esrt_data, &end); - efi_mem_reserve(esrt_data, esrt_data_size); + if (md.type == EFI_BOOT_SERVICES_DATA) + efi_mem_reserve(esrt_data, esrt_data_size); pr_debug("esrt-init: loaded.\n"); err_memunmap: diff --git a/drivers/firmware/google/vpd.c b/drivers/firmware/google/vpd.c index e4b40f2b46274a0871d1cb881732e8358a324112..9c0f7cf920afe561a83b62ac5b5dfb279bae6c1a 100644 --- a/drivers/firmware/google/vpd.c +++ b/drivers/firmware/google/vpd.c @@ -246,6 +246,7 @@ static int vpd_section_destroy(struct vpd_section *sec) sysfs_remove_bin_file(vpd_kobj, &sec->bin_attr); kfree(sec->raw_name); memunmap(sec->baseaddr); + sec->enabled = false; } return 0; @@ -279,8 +280,10 @@ static int vpd_sections_init(phys_addr_t physaddr) ret = vpd_section_init("rw", &rw_vpd, physaddr + sizeof(struct vpd_cbmem) + header.ro_size, header.rw_size); - if (ret) + if (ret) { + vpd_section_destroy(&ro_vpd); return ret; + } } return 0; diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c index 0e2011636fbbb4af579a895227fe6b9fef8e27cf..c53c7ac992f86fbcfa69f425e031679e3a3d5840 100644 --- a/drivers/firmware/qemu_fw_cfg.c +++ b/drivers/firmware/qemu_fw_cfg.c @@ -582,9 +582,10 @@ static int fw_cfg_sysfs_remove(struct platform_device *pdev) { pr_debug("fw_cfg: unloading.\n"); fw_cfg_sysfs_cache_cleanup(); + sysfs_remove_file(fw_cfg_top_ko, &fw_cfg_rev_attr.attr); + fw_cfg_io_cleanup(); fw_cfg_kset_unregister_recursive(fw_cfg_fname_kset); fw_cfg_kobj_cleanup(fw_cfg_sel_ko); - fw_cfg_io_cleanup(); return 0; } diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c index e717f8dc39667c8839e85aedd910ae1c34007782..202d367a21e4bd7babdc0ecc8d89bf3eff8639f2 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/gpio-adp5588.c @@ -41,6 +41,8 @@ struct adp5588_gpio { uint8_t int_en[3]; uint8_t irq_mask[3]; uint8_t irq_stat[3]; + uint8_t int_input_en[3]; + uint8_t int_lvl_cached[3]; }; static int adp5588_gpio_read(struct i2c_client *client, u8 reg) @@ -173,12 +175,28 @@ static void adp5588_irq_bus_sync_unlock(struct irq_data *d) struct adp5588_gpio *dev = irq_data_get_irq_chip_data(d); int i; - for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) + for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) { + if (dev->int_input_en[i]) { + mutex_lock(&dev->lock); + dev->dir[i] &= ~dev->int_input_en[i]; + dev->int_input_en[i] = 0; + adp5588_gpio_write(dev->client, GPIO_DIR1 + i, + dev->dir[i]); + mutex_unlock(&dev->lock); + } + + if (dev->int_lvl_cached[i] != dev->int_lvl[i]) { + dev->int_lvl_cached[i] = dev->int_lvl[i]; + adp5588_gpio_write(dev->client, GPIO_INT_LVL1 + i, + dev->int_lvl[i]); + } + if (dev->int_en[i] ^ dev->irq_mask[i]) { dev->int_en[i] = dev->irq_mask[i]; adp5588_gpio_write(dev->client, GPIO_INT_EN1 + i, dev->int_en[i]); } + } mutex_unlock(&dev->irq_lock); } @@ -221,9 +239,7 @@ static int adp5588_irq_set_type(struct irq_data *d, unsigned int type) else return -EINVAL; - adp5588_gpio_direction_input(&dev->gpio_chip, gpio); - adp5588_gpio_write(dev->client, GPIO_INT_LVL1 + bank, - dev->int_lvl[bank]); + dev->int_input_en[bank] |= bit; return 0; } diff --git a/drivers/gpio/gpio-menz127.c b/drivers/gpio/gpio-menz127.c index e1037582e34d7f69da7b3e96586f288b1f723f0b..b2635326546e7d3ac2e675b01d21ad234e5cd52a 100644 --- a/drivers/gpio/gpio-menz127.c +++ b/drivers/gpio/gpio-menz127.c @@ -56,9 +56,9 @@ static int men_z127_debounce(struct gpio_chip *gc, unsigned gpio, rnd = fls(debounce) - 1; if (rnd && (debounce & BIT(rnd - 1))) - debounce = round_up(debounce, MEN_Z127_DB_MIN_US); + debounce = roundup(debounce, MEN_Z127_DB_MIN_US); else - debounce = round_down(debounce, MEN_Z127_DB_MIN_US); + debounce = rounddown(debounce, MEN_Z127_DB_MIN_US); if (debounce > MEN_Z127_DB_MAX_US) debounce = MEN_Z127_DB_MAX_US; diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index 4b80e996d976524398e6ad484dd2f552bcdbed65..1022fe8d09c79c1543b2bb7d6f677b148d779e05 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -497,9 +497,10 @@ static int ioh_gpio_probe(struct pci_dev *pdev, return 0; err_gpiochip_add: + chip = chip_save; while (--i >= 0) { - chip--; gpiochip_remove(&chip->gpio); + chip++; } kfree(chip_save); diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index 6029899789f3dbcfa51e2227d6b94a115bf0a3e5..2943dfc4c470742511c190dedce079a10066ce94 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -662,6 +662,8 @@ static int pxa_gpio_probe(struct platform_device *pdev) pchip->irq0 = irq0; pchip->irq1 = irq1; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; gpio_reg_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); if (!gpio_reg_base) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index fbaf974277dffd9c90e57f03037a4b3fe8fa6da5..1eb857e2f62f166339bce3ff3c673b7c256845f4 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -728,4 +728,4 @@ static int __init tegra_gpio_init(void) { return platform_driver_register(&tegra_gpio_driver); } -postcore_initcall(tegra_gpio_init); +subsys_initcall(tegra_gpio_init); diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index d6f3d9ee1350e422e3f373427d55d6ce8b6be565..33d4bd505b5b8de7f39be767e4f680235bf8da9d 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -48,8 +48,20 @@ struct acpi_gpio_chip { struct mutex conn_lock; struct gpio_chip *chip; struct list_head events; + struct list_head deferred_req_irqs_list_entry; }; +/* + * For gpiochips which call acpi_gpiochip_request_interrupts() before late_init + * (so builtin drivers) we register the ACPI GpioInt event handlers from a + * late_initcall_sync handler, so that other builtin drivers can register their + * OpRegions before the event handlers can run. This list contains gpiochips + * for which the acpi_gpiochip_request_interrupts() has been deferred. + */ +static DEFINE_MUTEX(acpi_gpio_deferred_req_irqs_lock); +static LIST_HEAD(acpi_gpio_deferred_req_irqs_list); +static bool acpi_gpio_deferred_req_irqs_done; + static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) { if (!gc->parent) @@ -193,7 +205,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares, irq_handler_t handler = NULL; struct gpio_desc *desc; unsigned long irqflags; - int ret, pin, irq; + int ret, pin, irq, value; if (!acpi_gpio_get_irq_resource(ares, &agpio)) return AE_OK; @@ -228,6 +240,8 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares, gpiod_direction_input(desc); + value = gpiod_get_value_cansleep(desc); + ret = gpiochip_lock_as_irq(chip, pin); if (ret) { dev_err(chip->parent, "Failed to lock GPIO as interrupt\n"); @@ -283,6 +297,17 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares, enable_irq_wake(irq); list_add_tail(&event->node, &acpi_gpio->events); + + /* + * Make sure we trigger the initial state of the IRQ when using RISING + * or FALLING. Note we run the handlers on late_init, the AML code + * may refer to OperationRegions from other (builtin) drivers which + * may be probed after us. + */ + if (((irqflags & IRQF_TRIGGER_RISING) && value == 1) || + ((irqflags & IRQF_TRIGGER_FALLING) && value == 0)) + handler(event->irq, event); + return AE_OK; fail_free_event: @@ -310,6 +335,7 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) struct acpi_gpio_chip *acpi_gpio; acpi_handle handle; acpi_status status; + bool defer; if (!chip->parent || !chip->to_irq) return; @@ -322,6 +348,16 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) if (ACPI_FAILURE(status)) return; + mutex_lock(&acpi_gpio_deferred_req_irqs_lock); + defer = !acpi_gpio_deferred_req_irqs_done; + if (defer) + list_add(&acpi_gpio->deferred_req_irqs_list_entry, + &acpi_gpio_deferred_req_irqs_list); + mutex_unlock(&acpi_gpio_deferred_req_irqs_lock); + + if (defer) + return; + acpi_walk_resources(handle, "_AEI", acpi_gpiochip_request_interrupt, acpi_gpio); } @@ -352,6 +388,11 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) if (ACPI_FAILURE(status)) return; + mutex_lock(&acpi_gpio_deferred_req_irqs_lock); + if (!list_empty(&acpi_gpio->deferred_req_irqs_list_entry)) + list_del_init(&acpi_gpio->deferred_req_irqs_list_entry); + mutex_unlock(&acpi_gpio_deferred_req_irqs_lock); + list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) { struct gpio_desc *desc; @@ -1065,6 +1106,7 @@ void acpi_gpiochip_add(struct gpio_chip *chip) acpi_gpio->chip = chip; INIT_LIST_HEAD(&acpi_gpio->events); + INIT_LIST_HEAD(&acpi_gpio->deferred_req_irqs_list_entry); status = acpi_attach_data(handle, acpi_gpio_chip_dh, acpi_gpio); if (ACPI_FAILURE(status)) { @@ -1210,3 +1252,29 @@ bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id) return con_id == NULL; } + +/* Run deferred acpi_gpiochip_request_interrupts() */ +static int acpi_gpio_handle_deferred_request_interrupts(void) +{ + struct acpi_gpio_chip *acpi_gpio, *tmp; + + mutex_lock(&acpi_gpio_deferred_req_irqs_lock); + list_for_each_entry_safe(acpi_gpio, tmp, + &acpi_gpio_deferred_req_irqs_list, + deferred_req_irqs_list_entry) { + acpi_handle handle; + + handle = ACPI_HANDLE(acpi_gpio->chip->parent); + acpi_walk_resources(handle, "_AEI", + acpi_gpiochip_request_interrupt, acpi_gpio); + + list_del_init(&acpi_gpio->deferred_req_irqs_list_entry); + } + + acpi_gpio_deferred_req_irqs_done = true; + mutex_unlock(&acpi_gpio_deferred_req_irqs_lock); + + return 0; +} +/* We must use _sync so that this runs after the first deferred_probe run */ +late_initcall_sync(acpi_gpio_handle_deferred_request_interrupts); diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index ba38f530e4037ef81f24d18a00aba7449762e304..ee8c046cab62ede7ab7c0b70d5a87285a5c6a79a 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -31,6 +31,7 @@ static int of_gpiochip_match_node_and_xlate(struct gpio_chip *chip, void *data) struct of_phandle_args *gpiospec = data; return chip->gpiodev->dev.of_node == gpiospec->np && + chip->of_xlate && chip->of_xlate(chip, gpiospec, NULL) >= 0; } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 3396bbcd6cdb94cc0ab6135dd1e77a9013aa20ff..fb538c462cda696ecb16c03b4978bc7685f9c320 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -489,7 +489,7 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) if (ret) goto out_free_descs; lh->descs[i] = desc; - count = i; + count = i + 1; if (lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW) set_bit(FLAG_ACTIVE_LOW, &desc->flags); diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 3d4d0634c9ddd560797e2d85c71f271a83709d3e..7a3d9658d74c51074f4ea54bfb5863e39a7c168c 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -88,7 +88,7 @@ struct acpi_gpio_info { }; /* gpio suffixes used for ACPI and device tree lookup */ -static const char * const gpio_suffixes[] = { "gpios", "gpio" }; +static __maybe_unused const char * const gpio_suffixes[] = { "gpios", "gpio" }; #ifdef CONFIG_OF_GPIO struct gpio_desc *of_find_gpio(struct device *dev, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c index 1ae5ae8c45a45e20b21d42fffcb9e6c6d9ceaf4e..1a75a6b9ab2fb6b904ac1934e9bf2e3547e7ea06 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c @@ -569,6 +569,7 @@ static const struct amdgpu_px_quirk amdgpu_px_quirk_list[] = { { 0x1002, 0x6900, 0x1002, 0x0124, AMDGPU_PX_QUIRK_FORCE_ATPX }, { 0x1002, 0x6900, 0x1028, 0x0812, AMDGPU_PX_QUIRK_FORCE_ATPX }, { 0x1002, 0x6900, 0x1028, 0x0813, AMDGPU_PX_QUIRK_FORCE_ATPX }, + { 0x1002, 0x6900, 0x1025, 0x125A, AMDGPU_PX_QUIRK_FORCE_ATPX }, { 0x1002, 0x67DF, 0x1028, 0x0774, AMDGPU_PX_QUIRK_FORCE_ATPX }, { 0, 0, 0, 0, 0 }, }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c index fd435a96481c2f1c019bd4d2303ebbb9b590adad..e8d9479615c955ac2c624e12f41e89e4b081b371 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c @@ -715,12 +715,14 @@ static int amdgpu_cgs_get_firmware_info(struct cgs_device *cgs_device, break; case CHIP_POLARIS10: if (type == CGS_UCODE_ID_SMU) { - if ((adev->pdev->device == 0x67df) && - ((adev->pdev->revision == 0xe0) || - (adev->pdev->revision == 0xe3) || - (adev->pdev->revision == 0xe4) || - (adev->pdev->revision == 0xe5) || - (adev->pdev->revision == 0xe7) || + if (((adev->pdev->device == 0x67df) && + ((adev->pdev->revision == 0xe0) || + (adev->pdev->revision == 0xe3) || + (adev->pdev->revision == 0xe4) || + (adev->pdev->revision == 0xe5) || + (adev->pdev->revision == 0xe7) || + (adev->pdev->revision == 0xef))) || + ((adev->pdev->device == 0x6fdf) && (adev->pdev->revision == 0xef))) { info->is_kicker = true; strcpy(fw_name, "amdgpu/polaris10_k_smc.bin"); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 5f892ad6476edcccec4c4e7cb9b05d9b0db303c2..44aa58ab55d0c3535081e6cae550d474d0b457b9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -37,6 +37,7 @@ static int amdgpu_cs_user_fence_chunk(struct amdgpu_cs_parser *p, { struct drm_gem_object *gobj; unsigned long size; + int r; gobj = drm_gem_object_lookup(p->filp, data->handle); if (gobj == NULL) @@ -48,20 +49,26 @@ static int amdgpu_cs_user_fence_chunk(struct amdgpu_cs_parser *p, p->uf_entry.tv.shared = true; p->uf_entry.user_pages = NULL; - size = amdgpu_bo_size(p->uf_entry.robj); - if (size != PAGE_SIZE || (data->offset + 8) > size) - return -EINVAL; - - *offset = data->offset; - drm_gem_object_put_unlocked(gobj); + size = amdgpu_bo_size(p->uf_entry.robj); + if (size != PAGE_SIZE || (data->offset + 8) > size) { + r = -EINVAL; + goto error_unref; + } + if (amdgpu_ttm_tt_get_usermm(p->uf_entry.robj->tbo.ttm)) { - amdgpu_bo_unref(&p->uf_entry.robj); - return -EINVAL; + r = -EINVAL; + goto error_unref; } + *offset = data->offset; + return 0; + +error_unref: + amdgpu_bo_unref(&p->uf_entry.robj); + return r; } static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 0f16986ec5bc44356c19e9a7988a57e4b35f05bb..4dd68d8213538e548a557cff6229261e75ee1306 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -500,6 +500,7 @@ static const struct pci_device_id pciidlist[] = { {0x1002, 0x67CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10}, {0x1002, 0x67CC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10}, {0x1002, 0x67CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10}, + {0x1002, 0x6FDF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10}, /* Polaris12 */ {0x1002, 0x6980, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12}, {0x1002, 0x6981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12}, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index 8c2204c7b3847c3ce18042b48d70516155b843e5..7ad8fa891ce6b97bac4390eb0bd377d4b280b1d5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -134,6 +134,11 @@ psp_cmd_submit_buf(struct psp_context *psp, msleep(1); } + if (ucode) { + ucode->tmr_mc_addr_lo = psp->cmd_buf_mem->resp.fw_addr_lo; + ucode->tmr_mc_addr_hi = psp->cmd_buf_mem->resp.fw_addr_hi; + } + return ret; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h index 30b5500dc152140ca5ef49f3d6f217e04cdf2fc8..fa7b25e1e5d2990b7e2aa0e1e7ad6374dc3f2d34 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h @@ -172,6 +172,7 @@ enum AMDGPU_UCODE_ID { AMDGPU_UCODE_ID_SMC, AMDGPU_UCODE_ID_UVD, AMDGPU_UCODE_ID_VCE, + AMDGPU_UCODE_ID_VCN, AMDGPU_UCODE_ID_MAXIMUM, }; @@ -204,6 +205,9 @@ struct amdgpu_firmware_info { void *kaddr; /* ucode_size_bytes */ uint32_t ucode_size; + /* starting tmr mc address */ + uint32_t tmr_mc_addr_lo; + uint32_t tmr_mc_addr_hi; }; void amdgpu_ucode_print_mc_hdr(const struct common_firmware_header *hdr); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index 9fc3d387eae3eb73a17035aca85c6f9ddda79503..fb36425e21ffa17ce962b39ea7f9f23eed233a0c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -231,6 +231,8 @@ int amdgpu_vce_suspend(struct amdgpu_device *adev) { int i; + cancel_delayed_work_sync(&adev->vce.idle_work); + if (adev->vce.vcpu_bo == NULL) return 0; @@ -241,7 +243,6 @@ int amdgpu_vce_suspend(struct amdgpu_device *adev) if (i == AMDGPU_MAX_VCE_HANDLES) return 0; - cancel_delayed_work_sync(&adev->vce.idle_work); /* TODO: suspending running encoding sessions isn't supported */ return -EINVAL; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c index 308a9755eae39b2582bc20e00d8c6b3ce7e91e14..fca1b10628a6756a550e97c5398f2aa0b5c8827b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c @@ -93,9 +93,10 @@ int amdgpu_vcn_sw_init(struct amdgpu_device *adev) version_major, version_minor, family_id); - bo_size = AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8) - + AMDGPU_VCN_STACK_SIZE + AMDGPU_VCN_HEAP_SIZE + bo_size = AMDGPU_VCN_STACK_SIZE + AMDGPU_VCN_HEAP_SIZE + AMDGPU_VCN_SESSION_SIZE * 40; + if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) + bo_size += AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8); r = amdgpu_bo_create_kernel(adev, bo_size, PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, &adev->vcn.vcpu_bo, &adev->vcn.gpu_addr, &adev->vcn.cpu_addr); @@ -154,11 +155,11 @@ int amdgpu_vcn_suspend(struct amdgpu_device *adev) unsigned size; void *ptr; + cancel_delayed_work_sync(&adev->vcn.idle_work); + if (adev->vcn.vcpu_bo == NULL) return 0; - cancel_delayed_work_sync(&adev->vcn.idle_work); - size = amdgpu_bo_size(adev->vcn.vcpu_bo); ptr = adev->vcn.cpu_addr; @@ -191,11 +192,13 @@ int amdgpu_vcn_resume(struct amdgpu_device *adev) unsigned offset; hdr = (const struct common_firmware_header *)adev->vcn.fw->data; - offset = le32_to_cpu(hdr->ucode_array_offset_bytes); - memcpy_toio(adev->vcn.cpu_addr, adev->vcn.fw->data + offset, - le32_to_cpu(hdr->ucode_size_bytes)); - size -= le32_to_cpu(hdr->ucode_size_bytes); - ptr += le32_to_cpu(hdr->ucode_size_bytes); + if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) { + offset = le32_to_cpu(hdr->ucode_array_offset_bytes); + memcpy_toio(adev->vcn.cpu_addr, adev->vcn.fw->data + offset, + le32_to_cpu(hdr->ucode_size_bytes)); + size -= le32_to_cpu(hdr->ucode_size_bytes); + ptr += le32_to_cpu(hdr->ucode_size_bytes); + } memset_io(ptr, 0, size); } diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index a7e54820a330d70fccf53584722f603fd07ea20c..85bcd236890ec3c2e390e3911834bcf24a5a3f46 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -5479,6 +5479,11 @@ static int gfx_v8_0_set_powergating_state(void *handle, if (amdgpu_sriov_vf(adev)) return 0; + if (adev->pg_flags & (AMD_PG_SUPPORT_GFX_SMG | + AMD_PG_SUPPORT_RLC_SMU_HS | + AMD_PG_SUPPORT_CP | + AMD_PG_SUPPORT_GFX_DMG)) + adev->gfx.rlc.funcs->enter_safe_mode(adev); switch (adev->asic_type) { case CHIP_CARRIZO: case CHIP_STONEY: @@ -5527,7 +5532,11 @@ static int gfx_v8_0_set_powergating_state(void *handle, default: break; } - + if (adev->pg_flags & (AMD_PG_SUPPORT_GFX_SMG | + AMD_PG_SUPPORT_RLC_SMU_HS | + AMD_PG_SUPPORT_CP | + AMD_PG_SUPPORT_GFX_DMG)) + adev->gfx.rlc.funcs->exit_safe_mode(adev); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index 1a30c54a0889f20e451389e495ba562d5549a1c0..3981915e2311f72735841088e939ee7898211954 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -3113,7 +3113,7 @@ static void gfx_v9_0_enter_rlc_safe_mode(struct amdgpu_device *adev) /* wait for RLC_SAFE_MODE */ for (i = 0; i < adev->usec_timeout; i++) { - if (!REG_GET_FIELD(SOC15_REG_OFFSET(GC, 0, mmRLC_SAFE_MODE), RLC_SAFE_MODE, CMD)) + if (!REG_GET_FIELD(RREG32_SOC15(GC, 0, mmRLC_SAFE_MODE), RLC_SAFE_MODE, CMD)) break; udelay(1); } diff --git a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c index 3bbf2ccfca89c547f5e37623acb62e12e6d3d512..c76073b422d6cd1ce6a0edb8783e95acc029dab9 100644 --- a/drivers/gpu/drm/amd/amdgpu/kv_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/kv_dpm.c @@ -1352,8 +1352,6 @@ static int kv_dpm_enable(struct amdgpu_device *adev) return ret; } - kv_update_current_ps(adev, adev->pm.dpm.boot_ps); - if (adev->irq.installed && amdgpu_is_internal_thermal_sensor(adev->pm.int_thermal_type)) { ret = kv_set_thermal_temperature_range(adev, KV_TEMP_RANGE_MIN, KV_TEMP_RANGE_MAX); @@ -3054,7 +3052,7 @@ static int kv_dpm_hw_init(void *handle) else adev->pm.dpm_enabled = true; mutex_unlock(&adev->pm.mutex); - + amdgpu_pm_compute_clocks(adev); return ret; } diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c index f7cf994b1da2871a4437655f8306cf9bcb284468..86db90ff693a9df799725da38307440366da5cbc 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v10_0.c @@ -78,6 +78,9 @@ psp_v10_0_get_fw_type(struct amdgpu_firmware_info *ucode, enum psp_gfx_fw_type * case AMDGPU_UCODE_ID_VCE: *type = GFX_FW_TYPE_VCE; break; + case AMDGPU_UCODE_ID_VCN: + *type = GFX_FW_TYPE_VCN; + break; case AMDGPU_UCODE_ID_MAXIMUM: default: return -EINVAL; diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.c b/drivers/gpu/drm/amd/amdgpu/si_dpm.c index 6f1dea157a7753b70570e4a9d3d7064f1c4aeaa0..55613f425931ddfff43dc2370f55b5c97c0b48af 100644 --- a/drivers/gpu/drm/amd/amdgpu/si_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/si_dpm.c @@ -6884,7 +6884,6 @@ static int si_dpm_enable(struct amdgpu_device *adev) si_enable_auto_throttle_source(adev, AMDGPU_DPM_AUTO_THROTTLE_SRC_THERMAL, true); si_thermal_start_thermal_controller(adev); - ni_update_current_ps(adev, boot_ps); return 0; } @@ -7758,7 +7757,7 @@ static int si_dpm_hw_init(void *handle) else adev->pm.dpm_enabled = true; mutex_unlock(&adev->pm.mutex); - + amdgpu_pm_compute_clocks(adev); return ret; } diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c index 5183b46563f6cd4311b94cd2bd628f558427aec4..242dfb1433d263cb270a185b11c21486562bf489 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c @@ -899,7 +899,7 @@ static const struct amdgpu_ring_funcs vce_v3_0_ring_phys_funcs = { .emit_frame_size = 4 + /* vce_v3_0_emit_pipeline_sync */ 6, /* amdgpu_vce_ring_emit_fence x1 no user fence */ - .emit_ib_size = 5, /* vce_v3_0_ring_emit_ib */ + .emit_ib_size = 4, /* amdgpu_vce_ring_emit_ib */ .emit_ib = amdgpu_vce_ring_emit_ib, .emit_fence = amdgpu_vce_ring_emit_fence, .test_ring = amdgpu_vce_ring_test_ring, @@ -923,7 +923,7 @@ static const struct amdgpu_ring_funcs vce_v3_0_ring_vm_funcs = { 6 + /* vce_v3_0_emit_vm_flush */ 4 + /* vce_v3_0_emit_pipeline_sync */ 6 + 6, /* amdgpu_vce_ring_emit_fence x2 vm fence */ - .emit_ib_size = 4, /* amdgpu_vce_ring_emit_ib */ + .emit_ib_size = 5, /* vce_v3_0_ring_emit_ib */ .emit_ib = vce_v3_0_ring_emit_ib, .emit_vm_flush = vce_v3_0_emit_vm_flush, .emit_pipeline_sync = vce_v3_0_emit_pipeline_sync, diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c index a098712bdd2fff7291010b3536dfed0ad514eb69..f7b8caccab9fe1ab2d0c53eb8a9acdaaef98efa0 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c @@ -91,6 +91,16 @@ static int vcn_v1_0_sw_init(void *handle) if (r) return r; + if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { + const struct common_firmware_header *hdr; + hdr = (const struct common_firmware_header *)adev->vcn.fw->data; + adev->firmware.ucode[AMDGPU_UCODE_ID_VCN].ucode_id = AMDGPU_UCODE_ID_VCN; + adev->firmware.ucode[AMDGPU_UCODE_ID_VCN].fw = adev->vcn.fw; + adev->firmware.fw_size += + ALIGN(le32_to_cpu(hdr->ucode_size_bytes), PAGE_SIZE); + DRM_INFO("PSP loading VCN firmware\n"); + } + r = amdgpu_vcn_resume(adev); if (r) return r; @@ -248,26 +258,38 @@ static int vcn_v1_0_resume(void *handle) static void vcn_v1_0_mc_resume(struct amdgpu_device *adev) { uint32_t size = AMDGPU_GPU_PAGE_ALIGN(adev->vcn.fw->size + 4); - - WREG32_SOC15(UVD, 0, mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW, + uint32_t offset; + + if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { + WREG32_SOC15(UVD, 0, mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW, + (adev->firmware.ucode[AMDGPU_UCODE_ID_VCN].tmr_mc_addr_lo)); + WREG32_SOC15(UVD, 0, mmUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH, + (adev->firmware.ucode[AMDGPU_UCODE_ID_VCN].tmr_mc_addr_hi)); + WREG32_SOC15(UVD, 0, mmUVD_VCPU_CACHE_OFFSET0, 0); + offset = 0; + } else { + WREG32_SOC15(UVD, 0, mmUVD_LMI_VCPU_CACHE_64BIT_BAR_LOW, lower_32_bits(adev->vcn.gpu_addr)); - WREG32_SOC15(UVD, 0, mmUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH, + WREG32_SOC15(UVD, 0, mmUVD_LMI_VCPU_CACHE_64BIT_BAR_HIGH, upper_32_bits(adev->vcn.gpu_addr)); - WREG32_SOC15(UVD, 0, mmUVD_VCPU_CACHE_OFFSET0, - AMDGPU_UVD_FIRMWARE_OFFSET >> 3); + offset = size; + WREG32_SOC15(UVD, 0, mmUVD_VCPU_CACHE_OFFSET0, + AMDGPU_UVD_FIRMWARE_OFFSET >> 3); + } + WREG32_SOC15(UVD, 0, mmUVD_VCPU_CACHE_SIZE0, size); WREG32_SOC15(UVD, 0, mmUVD_LMI_VCPU_CACHE1_64BIT_BAR_LOW, - lower_32_bits(adev->vcn.gpu_addr + size)); + lower_32_bits(adev->vcn.gpu_addr + offset)); WREG32_SOC15(UVD, 0, mmUVD_LMI_VCPU_CACHE1_64BIT_BAR_HIGH, - upper_32_bits(adev->vcn.gpu_addr + size)); + upper_32_bits(adev->vcn.gpu_addr + offset)); WREG32_SOC15(UVD, 0, mmUVD_VCPU_CACHE_OFFSET1, 0); WREG32_SOC15(UVD, 0, mmUVD_VCPU_CACHE_SIZE1, AMDGPU_VCN_HEAP_SIZE); WREG32_SOC15(UVD, 0, mmUVD_LMI_VCPU_CACHE2_64BIT_BAR_LOW, - lower_32_bits(adev->vcn.gpu_addr + size + AMDGPU_VCN_HEAP_SIZE)); + lower_32_bits(adev->vcn.gpu_addr + offset + AMDGPU_VCN_HEAP_SIZE)); WREG32_SOC15(UVD, 0, mmUVD_LMI_VCPU_CACHE2_64BIT_BAR_HIGH, - upper_32_bits(adev->vcn.gpu_addr + size + AMDGPU_VCN_HEAP_SIZE)); + upper_32_bits(adev->vcn.gpu_addr + offset + AMDGPU_VCN_HEAP_SIZE)); WREG32_SOC15(UVD, 0, mmUVD_VCPU_CACHE_OFFSET2, 0); WREG32_SOC15(UVD, 0, mmUVD_VCPU_CACHE_SIZE2, AMDGPU_VCN_STACK_SIZE + (AMDGPU_VCN_SESSION_SIZE * 40)); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index c74cf22a1ed9d5d7d0c7c7e35e31786f6464161c..3ae88dcff08d1f9dc09b84993dafcec44f702cbf 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -123,6 +123,8 @@ struct kfd_process *kfd_get_process(const struct task_struct *thread) return ERR_PTR(-EINVAL); process = find_process(thread); + if (!process) + return ERR_PTR(-EINVAL); return process; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c index 1dc31aa7278178010be505364a03f4d1ce4df2f0..12856de09f572b4a77be436b25364fca1e3be735 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c @@ -403,6 +403,49 @@ static const struct gpu_pt_config_reg DIDTConfig_Polaris12[] = { { ixDIDT_SQ_CTRL1, DIDT_SQ_CTRL1__MAX_POWER_MASK, DIDT_SQ_CTRL1__MAX_POWER__SHIFT, 0xffff, GPU_CONFIGREG_DIDT_IND }, { ixDIDT_SQ_CTRL_OCP, DIDT_SQ_CTRL_OCP__UNUSED_0_MASK, DIDT_SQ_CTRL_OCP__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_CTRL_OCP, DIDT_SQ_CTRL_OCP__OCP_MAX_POWER_MASK, DIDT_SQ_CTRL_OCP__OCP_MAX_POWER__SHIFT, 0xffff, GPU_CONFIGREG_DIDT_IND }, + + { ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__MAX_POWER_DELTA_MASK, DIDT_SQ_CTRL2__MAX_POWER_DELTA__SHIFT, 0x3853, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__UNUSED_0_MASK, DIDT_SQ_CTRL2__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__SHORT_TERM_INTERVAL_SIZE_MASK, DIDT_SQ_CTRL2__SHORT_TERM_INTERVAL_SIZE__SHIFT, 0x005a, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__UNUSED_1_MASK, DIDT_SQ_CTRL2__UNUSED_1__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__LONG_TERM_INTERVAL_RATIO_MASK, DIDT_SQ_CTRL2__LONG_TERM_INTERVAL_RATIO__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__UNUSED_2_MASK, DIDT_SQ_CTRL2__UNUSED_2__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + + { ixDIDT_SQ_STALL_CTRL, DIDT_SQ_STALL_CTRL__DIDT_STALL_CTRL_ENABLE_MASK, DIDT_SQ_STALL_CTRL__DIDT_STALL_CTRL_ENABLE__SHIFT, 0x0001, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_STALL_CTRL, DIDT_SQ_STALL_CTRL__DIDT_STALL_DELAY_HI_MASK, DIDT_SQ_STALL_CTRL__DIDT_STALL_DELAY_HI__SHIFT, 0x0001, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_STALL_CTRL, DIDT_SQ_STALL_CTRL__DIDT_STALL_DELAY_LO_MASK, DIDT_SQ_STALL_CTRL__DIDT_STALL_DELAY_LO__SHIFT, 0x0001, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_STALL_CTRL, DIDT_SQ_STALL_CTRL__DIDT_HI_POWER_THRESHOLD_MASK, DIDT_SQ_STALL_CTRL__DIDT_HI_POWER_THRESHOLD__SHIFT, 0x0ebb, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_STALL_CTRL, DIDT_SQ_STALL_CTRL__UNUSED_0_MASK, DIDT_SQ_STALL_CTRL__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + + { ixDIDT_SQ_TUNING_CTRL, DIDT_SQ_TUNING_CTRL__DIDT_TUNING_ENABLE_MASK, DIDT_SQ_TUNING_CTRL__DIDT_TUNING_ENABLE__SHIFT, 0x0001, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_TUNING_CTRL, DIDT_SQ_TUNING_CTRL__MAX_POWER_DELTA_HI_MASK, DIDT_SQ_TUNING_CTRL__MAX_POWER_DELTA_HI__SHIFT, 0x3853, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_TUNING_CTRL, DIDT_SQ_TUNING_CTRL__MAX_POWER_DELTA_LO_MASK, DIDT_SQ_TUNING_CTRL__MAX_POWER_DELTA_LO__SHIFT, 0x3153, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_TUNING_CTRL, DIDT_SQ_TUNING_CTRL__UNUSED_0_MASK, DIDT_SQ_TUNING_CTRL__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + + { ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__DIDT_CTRL_EN_MASK, DIDT_SQ_CTRL0__DIDT_CTRL_EN__SHIFT, 0x0001, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__USE_REF_CLOCK_MASK, DIDT_SQ_CTRL0__USE_REF_CLOCK__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__PHASE_OFFSET_MASK, DIDT_SQ_CTRL0__PHASE_OFFSET__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__DIDT_CTRL_RST_MASK, DIDT_SQ_CTRL0__DIDT_CTRL_RST__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__DIDT_CLK_EN_OVERRIDE_MASK, DIDT_SQ_CTRL0__DIDT_CLK_EN_OVERRIDE__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI_MASK, DIDT_SQ_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI__SHIFT, 0x0010, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO_MASK, DIDT_SQ_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO__SHIFT, 0x0010, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__UNUSED_0_MASK, DIDT_SQ_CTRL0__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + + { ixDIDT_TD_WEIGHT0_3, DIDT_TD_WEIGHT0_3__WEIGHT0_MASK, DIDT_TD_WEIGHT0_3__WEIGHT0__SHIFT, 0x000a, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_TD_WEIGHT0_3, DIDT_TD_WEIGHT0_3__WEIGHT1_MASK, DIDT_TD_WEIGHT0_3__WEIGHT1__SHIFT, 0x0010, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_TD_WEIGHT0_3, DIDT_TD_WEIGHT0_3__WEIGHT2_MASK, DIDT_TD_WEIGHT0_3__WEIGHT2__SHIFT, 0x0017, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_TD_WEIGHT0_3, DIDT_TD_WEIGHT0_3__WEIGHT3_MASK, DIDT_TD_WEIGHT0_3__WEIGHT3__SHIFT, 0x002f, GPU_CONFIGREG_DIDT_IND }, + + { ixDIDT_TD_WEIGHT4_7, DIDT_TD_WEIGHT4_7__WEIGHT4_MASK, DIDT_TD_WEIGHT4_7__WEIGHT4__SHIFT, 0x0046, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_TD_WEIGHT4_7, DIDT_TD_WEIGHT4_7__WEIGHT5_MASK, DIDT_TD_WEIGHT4_7__WEIGHT5__SHIFT, 0x005d, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_TD_WEIGHT4_7, DIDT_TD_WEIGHT4_7__WEIGHT6_MASK, DIDT_TD_WEIGHT4_7__WEIGHT6__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_TD_WEIGHT4_7, DIDT_TD_WEIGHT4_7__WEIGHT7_MASK, DIDT_TD_WEIGHT4_7__WEIGHT7__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + + { ixDIDT_TD_CTRL1, DIDT_TD_CTRL1__MIN_POWER_MASK, DIDT_TD_CTRL1__MIN_POWER__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, + { ixDIDT_TD_CTRL1, DIDT_TD_CTRL1__MAX_POWER_MASK, DIDT_TD_CTRL1__MAX_POWER__SHIFT, 0xffff, GPU_CONFIGREG_DIDT_IND }, + + { ixDIDT_TD_CTRL_OCP, DIDT_TD_CTRL_OCP__UNUSED_0_MASK, DIDT_TD_CTRL_OCP__UNUSED_0__SHIFT, 0x0000, GPU_CONFIGREG_DIDT_IND }, { ixDIDT_TD_CTRL_OCP, DIDT_TD_CTRL_OCP__OCP_MAX_POWER_MASK, DIDT_TD_CTRL_OCP__OCP_MAX_POWER__SHIFT, 0x00ff, GPU_CONFIGREG_DIDT_IND }, { ixDIDT_TD_CTRL2, DIDT_TD_CTRL2__MAX_POWER_DELTA_MASK, DIDT_TD_CTRL2__MAX_POWER_DELTA__SHIFT, 0x3fff, GPU_CONFIGREG_DIDT_IND }, diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c index e7fa67063cdcbf2b5257b7a86ce58f1c087341ef..cb9e1cd456b8c624daceb2d0ce0f6fb96e56624b 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c @@ -1142,7 +1142,7 @@ static int vega10_enable_psm_gc_edc_config(struct pp_hwmgr *hwmgr) for (count = 0; count < num_se; count++) { data = GRBM_GFX_INDEX__INSTANCE_BROADCAST_WRITES_MASK | GRBM_GFX_INDEX__SH_BROADCAST_WRITES_MASK | ( count << GRBM_GFX_INDEX__SE_INDEX__SHIFT); cgs_write_register(hwmgr->device, reg, data); - result |= vega10_program_didt_config_registers(hwmgr, PSMSEEDCStallPatternConfig_Vega10, VEGA10_CONFIGREG_DIDT); + result = vega10_program_didt_config_registers(hwmgr, PSMSEEDCStallPatternConfig_Vega10, VEGA10_CONFIGREG_DIDT); result |= vega10_program_didt_config_registers(hwmgr, PSMSEEDCStallDelayConfig_Vega10, VEGA10_CONFIGREG_DIDT); result |= vega10_program_didt_config_registers(hwmgr, PSMSEEDCCtrlResetConfig_Vega10, VEGA10_CONFIGREG_DIDT); result |= vega10_program_didt_config_registers(hwmgr, PSMSEEDCCtrlConfig_Vega10, VEGA10_CONFIGREG_DIDT); diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c index 17bca99e8ac825334c982122fec82f22ebac636c..7e2c341dfe5f52d756482b55acf552deaab79470 100644 --- a/drivers/gpu/drm/arm/malidp_hw.c +++ b/drivers/gpu/drm/arm/malidp_hw.c @@ -634,7 +634,8 @@ const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = { .vsync_irq = MALIDP500_DE_IRQ_VSYNC, }, .se_irq_map = { - .irq_mask = MALIDP500_SE_IRQ_CONF_MODE, + .irq_mask = MALIDP500_SE_IRQ_CONF_MODE | + MALIDP500_SE_IRQ_GLOBAL, .vsync_irq = 0, }, .dc_irq_map = { diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c index 94e7e3fa3408cf163fda7f81b40e76ca73ac4c96..16b8b310ae5c7036760b3d8b538b15b5f07bcfa6 100644 --- a/drivers/gpu/drm/arm/malidp_planes.c +++ b/drivers/gpu/drm/arm/malidp_planes.c @@ -23,6 +23,7 @@ /* Layer specific register offsets */ #define MALIDP_LAYER_FORMAT 0x000 +#define LAYER_FORMAT_MASK 0x3f #define MALIDP_LAYER_CONTROL 0x004 #define LAYER_ENABLE (1 << 0) #define LAYER_FLOWCFG_MASK 7 @@ -278,7 +279,9 @@ static void malidp_de_plane_update(struct drm_plane *plane, dest_w = plane->state->crtc_w; dest_h = plane->state->crtc_h; - malidp_hw_write(mp->hwdev, ms->format, mp->layer->base); + val = malidp_hw_read(mp->hwdev, mp->layer->base); + val = (val & ~LAYER_FORMAT_MASK) | ms->format; + malidp_hw_write(mp->hwdev, val, mp->layer->base); for (i = 0; i < ms->n_planes; i++) { /* calculate the offset for the layer's plane registers */ diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 79ce877bf45f258abb54359a1cb4322b8e27db15..3039936f8f3fc8a589f24cbb84a6e6566a39df6a 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -483,8 +483,9 @@ static irqreturn_t armada_drm_irq(int irq, void *arg) u32 v, stat = readl_relaxed(dcrtc->base + LCD_SPU_IRQ_ISR); /* - * This is rediculous - rather than writing bits to clear, we - * have to set the actual status register value. This is racy. + * Reading the ISR appears to clear bits provided CLEAN_SPU_IRQ_ISR + * is set. Writing has some other effect to acknowledge the IRQ - + * without this, we only get a single IRQ. */ writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ISR); @@ -1104,16 +1105,22 @@ armada_drm_crtc_set_property(struct drm_crtc *crtc, static int armada_drm_crtc_enable_vblank(struct drm_crtc *crtc) { struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); + unsigned long flags; + spin_lock_irqsave(&dcrtc->irq_lock, flags); armada_drm_crtc_enable_irq(dcrtc, VSYNC_IRQ_ENA); + spin_unlock_irqrestore(&dcrtc->irq_lock, flags); return 0; } static void armada_drm_crtc_disable_vblank(struct drm_crtc *crtc) { struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); + unsigned long flags; + spin_lock_irqsave(&dcrtc->irq_lock, flags); armada_drm_crtc_disable_irq(dcrtc, VSYNC_IRQ_ENA); + spin_unlock_irqrestore(&dcrtc->irq_lock, flags); } static const struct drm_crtc_funcs armada_crtc_funcs = { @@ -1221,6 +1228,7 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, CFG_PDWN64x66, dcrtc->base + LCD_SPU_SRAM_PARA1); writel_relaxed(0x2032ff81, dcrtc->base + LCD_SPU_DMA_CTRL1); writel_relaxed(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA); + readl_relaxed(dcrtc->base + LCD_SPU_IRQ_ISR); writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ISR); ret = devm_request_irq(dev, irq, armada_drm_irq, 0, "armada_drm_crtc", diff --git a/drivers/gpu/drm/armada/armada_hw.h b/drivers/gpu/drm/armada/armada_hw.h index 27319a8335e258cf12cb093c5c598523fbe307f3..345dc4d0851ef43bd73069679c3ec7fef8bfa073 100644 --- a/drivers/gpu/drm/armada/armada_hw.h +++ b/drivers/gpu/drm/armada/armada_hw.h @@ -160,6 +160,7 @@ enum { CFG_ALPHAM_GRA = 0x1 << 16, CFG_ALPHAM_CFG = 0x2 << 16, CFG_ALPHA_MASK = 0xff << 8, +#define CFG_ALPHA(x) ((x) << 8) CFG_PIXCMD_MASK = 0xff, }; diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c index edc44910d79fc7c65bce893d31b2caf9ce1d34e4..2076346b09ee98759eafd674582890d3693924c3 100644 --- a/drivers/gpu/drm/armada/armada_overlay.c +++ b/drivers/gpu/drm/armada/armada_overlay.c @@ -28,6 +28,7 @@ struct armada_ovl_plane_properties { uint16_t contrast; uint16_t saturation; uint32_t colorkey_mode; + uint32_t colorkey_enable; }; struct armada_ovl_plane { @@ -59,11 +60,13 @@ armada_ovl_update_attr(struct armada_ovl_plane_properties *prop, writel_relaxed(0x00002000, dcrtc->base + LCD_SPU_CBSH_HUE); spin_lock_irq(&dcrtc->irq_lock); - armada_updatel(prop->colorkey_mode | CFG_ALPHAM_GRA, - CFG_CKMODE_MASK | CFG_ALPHAM_MASK | CFG_ALPHA_MASK, - dcrtc->base + LCD_SPU_DMA_CTRL1); - - armada_updatel(ADV_GRACOLORKEY, 0, dcrtc->base + LCD_SPU_ADV_REG); + armada_updatel(prop->colorkey_mode, + CFG_CKMODE_MASK | CFG_ALPHAM_MASK | CFG_ALPHA_MASK, + dcrtc->base + LCD_SPU_DMA_CTRL1); + if (dcrtc->variant->has_spu_adv_reg) + armada_updatel(prop->colorkey_enable, + ADV_GRACOLORKEY | ADV_VIDCOLORKEY, + dcrtc->base + LCD_SPU_ADV_REG); spin_unlock_irq(&dcrtc->irq_lock); } @@ -339,8 +342,17 @@ static int armada_ovl_plane_set_property(struct drm_plane *plane, dplane->prop.colorkey_vb |= K2B(val); update_attr = true; } else if (property == priv->colorkey_mode_prop) { - dplane->prop.colorkey_mode &= ~CFG_CKMODE_MASK; - dplane->prop.colorkey_mode |= CFG_CKMODE(val); + if (val == CKMODE_DISABLE) { + dplane->prop.colorkey_mode = + CFG_CKMODE(CKMODE_DISABLE) | + CFG_ALPHAM_CFG | CFG_ALPHA(255); + dplane->prop.colorkey_enable = 0; + } else { + dplane->prop.colorkey_mode = + CFG_CKMODE(val) | + CFG_ALPHAM_GRA | CFG_ALPHA(0); + dplane->prop.colorkey_enable = ADV_GRACOLORKEY; + } update_attr = true; } else if (property == priv->brightness_prop) { dplane->prop.brightness = val - 256; @@ -470,7 +482,9 @@ int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs) dplane->prop.colorkey_yr = 0xfefefe00; dplane->prop.colorkey_ug = 0x01010100; dplane->prop.colorkey_vb = 0x01010100; - dplane->prop.colorkey_mode = CFG_CKMODE(CKMODE_RGB); + dplane->prop.colorkey_mode = CFG_CKMODE(CKMODE_RGB) | + CFG_ALPHAM_GRA | CFG_ALPHA(0); + dplane->prop.colorkey_enable = ADV_GRACOLORKEY; dplane->prop.brightness = 0; dplane->prop.contrast = 0x4000; dplane->prop.saturation = 0x4000; diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index b2431aee788795cfa078dbf4b5515c75dbe1961c..f5091827628ab2ab9d6040b42786b5231cffa13e 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -424,6 +424,18 @@ static void adv7511_hpd_work(struct work_struct *work) else status = connector_status_disconnected; + /* + * The bridge resets its registers on unplug. So when we get a plug + * event and we're already supposed to be powered, cycle the bridge to + * restore its state. + */ + if (status == connector_status_connected && + adv7511->connector.status == connector_status_disconnected && + adv7511->powered) { + regcache_mark_dirty(adv7511->regmap); + adv7511_power_on(adv7511); + } + if (adv7511->connector.status != status) { adv7511->connector.status = status; drm_kms_helper_hotplug_event(adv7511->connector.dev); diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c index 5131bfb94f065ceb20ba61713f990b76f11103cb..0cb69ee94ac16822965632f265202c8ffeea482a 100644 --- a/drivers/gpu/drm/bridge/sil-sii8620.c +++ b/drivers/gpu/drm/bridge/sil-sii8620.c @@ -788,6 +788,7 @@ static void sii8620_burst_rx_all(struct sii8620 *ctx) static void sii8620_fetch_edid(struct sii8620 *ctx) { u8 lm_ddc, ddc_cmd, int3, cbus; + unsigned long timeout; int fetched, i; int edid_len = EDID_LENGTH; u8 *edid; @@ -837,23 +838,31 @@ static void sii8620_fetch_edid(struct sii8620 *ctx) REG_DDC_CMD, ddc_cmd | VAL_DDC_CMD_ENH_DDC_READ_NO_ACK ); - do { - int3 = sii8620_readb(ctx, REG_INTR3); + int3 = 0; + timeout = jiffies + msecs_to_jiffies(200); + for (;;) { cbus = sii8620_readb(ctx, REG_CBUS_STATUS); - - if (int3 & BIT_DDC_CMD_DONE) - break; - - if (!(cbus & BIT_CBUS_STATUS_CBUS_CONNECTED)) { + if (~cbus & BIT_CBUS_STATUS_CBUS_CONNECTED) { + kfree(edid); + edid = NULL; + goto end; + } + if (int3 & BIT_DDC_CMD_DONE) { + if (sii8620_readb(ctx, REG_DDC_DOUT_CNT) + >= FETCH_SIZE) + break; + } else { + int3 = sii8620_readb(ctx, REG_INTR3); + } + if (time_is_before_jiffies(timeout)) { + ctx->error = -ETIMEDOUT; + dev_err(ctx->dev, "timeout during EDID read\n"); kfree(edid); edid = NULL; goto end; } - } while (1); - - sii8620_readb(ctx, REG_DDC_STATUS); - while (sii8620_readb(ctx, REG_DDC_DOUT_CNT) < FETCH_SIZE) usleep_range(10, 20); + } sii8620_read_buf(ctx, REG_DDC_DATA, edid + fetched, FETCH_SIZE); if (fetched + FETCH_SIZE == EDID_LENGTH) { @@ -1036,23 +1045,23 @@ static void sii8620_set_format(struct sii8620 *ctx) BIT_M3_P0CTRL_MHL3_P0_PIXEL_MODE_PACKED, ctx->use_packed_pixel ? ~0 : 0); } else { - if (ctx->use_packed_pixel) + if (ctx->use_packed_pixel) { sii8620_write_seq_static(ctx, REG_VID_MODE, BIT_VID_MODE_M1080P, REG_MHL_TOP_CTL, BIT_MHL_TOP_CTL_MHL_PP_SEL | 1, REG_MHLTX_CTL6, 0x60 ); - else + } else { sii8620_write_seq_static(ctx, REG_VID_MODE, 0, REG_MHL_TOP_CTL, 1, REG_MHLTX_CTL6, 0xa0 ); + } } if (ctx->use_packed_pixel) - out_fmt = VAL_TPI_FORMAT(YCBCR422, FULL) | - BIT_TPI_OUTPUT_CSCMODE709; + out_fmt = VAL_TPI_FORMAT(YCBCR422, FULL); else out_fmt = VAL_TPI_FORMAT(RGB, FULL); @@ -1187,7 +1196,7 @@ static void sii8620_start_hdmi(struct sii8620 *ctx) int clk = ctx->pixel_clock * (ctx->use_packed_pixel ? 2 : 3); int i; - for (i = 0; i < ARRAY_SIZE(clk_spec); ++i) + for (i = 0; i < ARRAY_SIZE(clk_spec) - 1; ++i) if (clk < clk_spec[i].max_clk) break; diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index a89fc651f3dfb244605924bb0f3e3e59bce4d7bc..448a5a36268060259ae3dbfb945cde9efd1ad4cb 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -122,6 +122,9 @@ static const struct edid_quirk { /* CPT panel of Asus UX303LA reports 8 bpc, but is a 6 bpc panel */ { "CPT", 0x17df, EDID_QUIRK_FORCE_6BPC }, + /* SDC panel of Lenovo B50-80 reports 8 bpc, but is a 6 bpc panel */ + { "SDC", 0x3652, EDID_QUIRK_FORCE_6BPC }, + /* Belinea 10 15 55 */ { "MAX", 1516, EDID_QUIRK_PREFER_LARGE_60 }, { "MAX", 0x77e, EDID_QUIRK_PREFER_LARGE_60 }, diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index 7bcf5702c91ce7f14761e3ce5da7b34d2cdfc411..889c95d4feecc287dc48d0e18b730dc8055f4682 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -96,6 +96,8 @@ static int drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj, { int ret; + WARN_ON(*fence); + *fence = drm_syncobj_fence_get(syncobj); if (*fence) return 1; @@ -656,6 +658,9 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs, if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) { for (i = 0; i < count; ++i) { + if (entries[i].fence) + continue; + drm_syncobj_fence_get_or_add_callback(syncobjs[i], &entries[i].fence, &entries[i].syncobj_cb, diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index 6be5b53c3b279f42ee6dbcc445173fa539721ce5..f905c214fdd0e65a2cf1911680f9cfd7abad25e1 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -261,7 +261,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win, unsigned long val; val = readl(ctx->addr + DECON_WINCONx(win)); - val &= ~WINCONx_BPPMODE_MASK; + val &= WINCONx_ENWIN_F; switch (fb->format->format) { case DRM_FORMAT_XRGB1555: @@ -352,8 +352,8 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, writel(val, ctx->addr + DECON_VIDOSDxB(win)); } - val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) | - VIDOSD_Wx_ALPHA_B_F(0x0); + val = VIDOSD_Wx_ALPHA_R_F(0xff) | VIDOSD_Wx_ALPHA_G_F(0xff) | + VIDOSD_Wx_ALPHA_B_F(0xff); writel(val, ctx->addr + DECON_VIDOSDxC(win)); val = VIDOSD_Wx_ALPHA_R_F(0x0) | VIDOSD_Wx_ALPHA_G_F(0x0) | diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c index 0506b2b17ac1c45a1bea639cb37ed90075be3677..48f913d8208c45134e4f75977f49fb3928c5dd41 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c @@ -532,21 +532,25 @@ static int gsc_src_set_fmt(struct device *dev, u32 fmt) GSC_IN_CHROMA_ORDER_CRCB); break; case DRM_FORMAT_NV21: + cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV420_2P); + break; case DRM_FORMAT_NV61: - cfg |= (GSC_IN_CHROMA_ORDER_CRCB | - GSC_IN_YUV420_2P); + cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV422_2P); break; case DRM_FORMAT_YUV422: cfg |= GSC_IN_YUV422_3P; break; case DRM_FORMAT_YUV420: + cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV420_3P); + break; case DRM_FORMAT_YVU420: - cfg |= GSC_IN_YUV420_3P; + cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV420_3P); break; case DRM_FORMAT_NV12: + cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV420_2P); + break; case DRM_FORMAT_NV16: - cfg |= (GSC_IN_CHROMA_ORDER_CBCR | - GSC_IN_YUV420_2P); + cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV422_2P); break; default: dev_err(ippdrv->dev, "invalid target yuv order 0x%x.\n", fmt); @@ -806,18 +810,25 @@ static int gsc_dst_set_fmt(struct device *dev, u32 fmt) GSC_OUT_CHROMA_ORDER_CRCB); break; case DRM_FORMAT_NV21: - case DRM_FORMAT_NV61: cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV420_2P); break; + case DRM_FORMAT_NV61: + cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV422_2P); + break; case DRM_FORMAT_YUV422: + cfg |= GSC_OUT_YUV422_3P; + break; case DRM_FORMAT_YUV420: + cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV420_3P); + break; case DRM_FORMAT_YVU420: - cfg |= GSC_OUT_YUV420_3P; + cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV420_3P); break; case DRM_FORMAT_NV12: + cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV420_2P); + break; case DRM_FORMAT_NV16: - cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | - GSC_OUT_YUV420_2P); + cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV422_2P); break; default: dev_err(ippdrv->dev, "invalid target yuv order 0x%x.\n", fmt); diff --git a/drivers/gpu/drm/exynos/regs-gsc.h b/drivers/gpu/drm/exynos/regs-gsc.h index 4704a993cbb7f003a51b901ae9b291a9adc9fe09..16b39734115c93855d82a5de94e16cc5e2570940 100644 --- a/drivers/gpu/drm/exynos/regs-gsc.h +++ b/drivers/gpu/drm/exynos/regs-gsc.h @@ -138,6 +138,7 @@ #define GSC_OUT_YUV420_3P (3 << 4) #define GSC_OUT_YUV422_1P (4 << 4) #define GSC_OUT_YUV422_2P (5 << 4) +#define GSC_OUT_YUV422_3P (6 << 4) #define GSC_OUT_YUV444 (7 << 4) #define GSC_OUT_TILE_TYPE_MASK (1 << 2) #define GSC_OUT_TILE_C_16x8 (0 << 2) diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index 9bf4045cd679ab6598494e13440e3b4f23d60c78..73c672fc17c4a548314269de4d82d081be249cd0 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -42,6 +42,8 @@ #include #include +#include + #include "i915_drv.h" #include "gvt.h" @@ -953,7 +955,8 @@ static long intel_vgpu_ioctl(struct mdev_device *mdev, unsigned int cmd, } else if (cmd == VFIO_DEVICE_GET_REGION_INFO) { struct vfio_region_info info; struct vfio_info_cap caps = { .buf = NULL, .size = 0 }; - int i, ret; + unsigned int i; + int ret; struct vfio_region_info_cap_sparse_mmap *sparse = NULL; size_t size; int nr_areas = 1; @@ -1030,6 +1033,10 @@ static long intel_vgpu_ioctl(struct mdev_device *mdev, unsigned int cmd, if (info.index >= VFIO_PCI_NUM_REGIONS + vgpu->vdev.num_regions) return -EINVAL; + info.index = + array_index_nospec(info.index, + VFIO_PCI_NUM_REGIONS + + vgpu->vdev.num_regions); i = info.index - VFIO_PCI_NUM_REGIONS; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 90359c7954c8d66532808e82f8116121ac576ca5..f354cfe63f7be34a398c57209dd7fb5a74c0e5fe 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -687,10 +687,10 @@ flush_write_domain(struct drm_i915_gem_object *obj, unsigned int flush_domains) switch (obj->base.write_domain) { case I915_GEM_DOMAIN_GTT: - if (INTEL_GEN(dev_priv) >= 6 && !HAS_LLC(dev_priv)) { + if (!HAS_LLC(dev_priv)) { intel_runtime_pm_get(dev_priv); spin_lock_irq(&dev_priv->uncore.lock); - POSTING_READ_FW(RING_ACTHD(dev_priv->engine[RCS]->mmio_base)); + POSTING_READ_FW(RING_HEAD(dev_priv->engine[RCS]->mmio_base)); spin_unlock_irq(&dev_priv->uncore.lock); intel_runtime_pm_put(dev_priv); } @@ -3608,7 +3608,8 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, return -EBUSY; } - if (i915_gem_valid_gtt_space(vma, cache_level)) + if (!i915_vma_is_closed(vma) && + i915_gem_valid_gtt_space(vma, cache_level)) continue; ret = i915_vma_unbind(vma); diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c b/drivers/gpu/drm/i915/i915_gem_userptr.c index 709efe2357eac9948ba71a76e11c02ace9f6ae4c..05ae8c4a8a1b615e272d4bb20d09b748f6b1e885 100644 --- a/drivers/gpu/drm/i915/i915_gem_userptr.c +++ b/drivers/gpu/drm/i915/i915_gem_userptr.c @@ -782,6 +782,9 @@ i915_gem_userptr_ioctl(struct drm_device *dev, void *data, struct drm_file *file I915_USERPTR_UNSYNCHRONIZED)) return -EINVAL; + if (!args->user_size) + return -EINVAL; + if (offset_in_page(args->user_ptr | args->user_size)) return -EINVAL; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index be813b2738c1526bcd4a1b7395ef1453e279910f..2e706f1abe64f0da52a0f2406b1b308113a02b7c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -8462,6 +8462,7 @@ enum skl_power_gate { #define TRANS_MSA_10_BPC (2<<5) #define TRANS_MSA_12_BPC (3<<5) #define TRANS_MSA_16_BPC (4<<5) +#define TRANS_MSA_CEA_RANGE (1<<3) /* LCPLL Control */ #define LCPLL_CTL _MMIO(0x130040) diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index 02d1a5eacb00ef5fa89deeaaa41318f81ebac902..76eed1fdac0960f19ccdefe91d6cb7dbe4da7358 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -430,6 +430,7 @@ i915_vma_insert(struct i915_vma *vma, u64 size, u64 alignment, u64 flags) u64 start, end; int ret; + GEM_BUG_ON(i915_vma_is_closed(vma)); GEM_BUG_ON(vma->flags & (I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND)); GEM_BUG_ON(drm_mm_node_allocated(&vma->node)); @@ -590,7 +591,9 @@ static void i915_vma_destroy(struct i915_vma *vma) GEM_BUG_ON(i915_gem_active_isset(&vma->last_read[i])); GEM_BUG_ON(i915_gem_active_isset(&vma->last_fence)); + list_del(&vma->obj_link); list_del(&vma->vm_link); + if (!i915_vma_is_ggtt(vma)) i915_ppgtt_put(i915_vm_to_ppgtt(vma->vm)); @@ -602,7 +605,6 @@ void i915_vma_close(struct i915_vma *vma) GEM_BUG_ON(i915_vma_is_closed(vma)); vma->flags |= I915_VMA_CLOSED; - list_del(&vma->obj_link); rb_erase(&vma->obj_node, &vma->obj->vma_tree); if (!i915_vma_is_active(vma) && !i915_vma_is_pinned(vma)) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 5e5fe03b638cbf2ee17206ccd4c6ee985134645e..3a4a581345c431dd3f2ba7235103913c77101751 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1396,6 +1396,10 @@ void intel_ddi_set_pipe_settings(const struct intel_crtc_state *crtc_state) WARN_ON(transcoder_is_dsi(cpu_transcoder)); temp = TRANS_MSA_SYNC_CLK; + + if (crtc_state->limited_color_range) + temp |= TRANS_MSA_CEA_RANGE; + switch (crtc_state->pipe_bpp) { case 18: temp |= TRANS_MSA_6_BPC; diff --git a/drivers/gpu/drm/i915/intel_lpe_audio.c b/drivers/gpu/drm/i915/intel_lpe_audio.c index 3bf65288ffffd51719d0c4e8ce934ccd2d2f59e3..8a541d0e3e80d512e8ab35f339743f99bce4cb9b 100644 --- a/drivers/gpu/drm/i915/intel_lpe_audio.c +++ b/drivers/gpu/drm/i915/intel_lpe_audio.c @@ -62,6 +62,7 @@ #include #include +#include #include #include @@ -127,9 +128,7 @@ lpe_audio_platdev_create(struct drm_i915_private *dev_priv) kfree(rsc); - pm_runtime_forbid(&platdev->dev); - pm_runtime_set_active(&platdev->dev); - pm_runtime_enable(&platdev->dev); + pm_runtime_no_callbacks(&platdev->dev); return platdev; diff --git a/drivers/gpu/drm/i915/intel_lspcon.c b/drivers/gpu/drm/i915/intel_lspcon.c index beb9baaf2f2e4e573956f1ea842c2963dce95bd7..f71fef10ecc6180a3fc8835bb864dbf24771f705 100644 --- a/drivers/gpu/drm/i915/intel_lspcon.c +++ b/drivers/gpu/drm/i915/intel_lspcon.c @@ -75,7 +75,7 @@ static enum drm_lspcon_mode lspcon_wait_mode(struct intel_lspcon *lspcon, lspcon_mode_name(mode)); wait_for((current_mode = lspcon_get_current_mode(lspcon)) == mode || - current_mode == DRM_LSPCON_MODE_INVALID, 100); + current_mode == DRM_LSPCON_MODE_INVALID, 400); if (current_mode != mode) DRM_DEBUG_KMS("LSPCON mode hasn't settled\n"); diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c index 56dd7a9a8e254a3e03e4bebb5fda75b8555abbba..dd5312b02a8d21749fb004d41db74ff4bc511b1a 100644 --- a/drivers/gpu/drm/imx/imx-ldb.c +++ b/drivers/gpu/drm/imx/imx-ldb.c @@ -612,6 +612,9 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) return PTR_ERR(imx_ldb->regmap); } + /* disable LDB by resetting the control register to POR default */ + regmap_write(imx_ldb->regmap, IOMUXC_GPR2, 0); + imx_ldb->dev = dev; if (of_id) @@ -652,14 +655,14 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) if (ret || i < 0 || i > 1) return -EINVAL; + if (!of_device_is_available(child)) + continue; + if (dual && i > 0) { dev_warn(dev, "dual-channel mode, ignoring second output\n"); continue; } - if (!of_device_is_available(child)) - continue; - channel = &imx_ldb->channel[i]; channel->ldb = imx_ldb; channel->chno = i; diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c index c512c75226fc4681deb715f254c9ea4802bfa796..45fbc4899032cdb72b354c53978141bfd34ec622 100644 --- a/drivers/gpu/drm/msm/dp/dp_aux.c +++ b/drivers/gpu/drm/msm/dp/dp_aux.c @@ -58,20 +58,26 @@ struct dp_aux_private { static void dp_aux_hex_dump(struct drm_dp_aux *drm_aux, struct drm_dp_aux_msg *msg) { - DEFINE_DYNAMIC_DEBUG_METADATA(ddm, "dp aux tracker"); + char prefix[64]; + int i, linelen, remaining = msg->size; + const int rowsize = 16; + u8 linebuf[64]; + struct dp_aux_private *aux = container_of(drm_aux, + struct dp_aux_private, drm_aux); - if (unlikely(ddm.flags & _DPRINTK_FLAGS_PRINT)) { - u8 buf[SZ_64]; - struct dp_aux_private *aux = container_of(drm_aux, - struct dp_aux_private, drm_aux); + snprintf(prefix, sizeof(prefix), "%s %s %4xh(%2zu): ", + aux->native ? "NAT" : "I2C", + aux->read ? "RD" : "WR", + msg->address, msg->size); - snprintf(buf, SZ_64, "[drm-dp] %5s %5s %5xh(%2zu): ", - aux->native ? "NATIVE" : "I2C", - aux->read ? "READ" : "WRITE", - msg->address, msg->size); + for (i = 0; i < msg->size; i += rowsize) { + linelen = min(remaining, rowsize); + remaining -= rowsize; - print_hex_dump(KERN_DEBUG, buf, DUMP_PREFIX_NONE, - 8, 1, msg->buffer, msg->size, false); + hex_dump_to_buffer(msg->buffer + i, linelen, rowsize, 1, + linebuf, sizeof(linebuf), false); + + pr_debug("%s%s\n", prefix, linebuf); } } #else @@ -492,30 +498,42 @@ static ssize_t dp_aux_transfer_debug(struct drm_dp_aux *drm_aux, goto end; } - if ((msg->address + msg->size) > SZ_16K) { + if ((msg->address + msg->size) > SZ_4K) { pr_err("invalid dpcd access: addr=0x%x, size=0x%x\n", msg->address + msg->size); goto address_error; } if (aux->native) { - if (aux->read) { - aux->dp_aux.reg = msg->address; + aux->dp_aux.reg = msg->address; + aux->dp_aux.read = aux->read; + aux->dp_aux.size = msg->size; - reinit_completion(&aux->comp); + reinit_completion(&aux->comp); + + if (aux->read) { timeout = wait_for_completion_timeout(&aux->comp, HZ); - if (!timeout) + if (!timeout) { pr_err("aux timeout for 0x%x\n", msg->address); - - aux->dp_aux.reg = 0xFFFF; + ret = -ETIMEDOUT; + goto end; + } memcpy(msg->buffer, aux->dpcd + msg->address, msg->size); - aux->aux_error_num = DP_AUX_ERR_NONE; } else { memcpy(aux->dpcd + msg->address, msg->buffer, msg->size); + + timeout = wait_for_completion_timeout(&aux->comp, HZ); + if (!timeout) { + pr_err("aux timeout for 0x%x\n", msg->address); + ret = -ETIMEDOUT; + goto end; + } } + + aux->aux_error_num = DP_AUX_ERR_NONE; } else { if (aux->read && msg->address == 0x50) { memcpy(msg->buffer, @@ -545,6 +563,10 @@ static ssize_t dp_aux_transfer_debug(struct drm_dp_aux *drm_aux, memset(msg->buffer, 0, msg->size); ret = msg->size; end: + aux->dp_aux.reg = 0xFFFF; + aux->dp_aux.read = true; + aux->dp_aux.size = 0; + mutex_unlock(&aux->mutex); return ret; } diff --git a/drivers/gpu/drm/msm/dp/dp_aux.h b/drivers/gpu/drm/msm/dp/dp_aux.h index 5ef9f750785e9466d19cab85438a76d898dda2b8..c0d0bf343fcd92acdd1c7f8794c3e3409c8df13d 100644 --- a/drivers/gpu/drm/msm/dp/dp_aux.h +++ b/drivers/gpu/drm/msm/dp/dp_aux.h @@ -43,8 +43,11 @@ enum dp_aux_error { struct dp_aux { u32 reg; + u32 size; u32 state; + bool read; + struct drm_dp_aux *drm_aux; int (*drm_aux_register)(struct dp_aux *aux); void (*drm_aux_deregister)(struct dp_aux *aux); diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c index c771d36cc947dd33c580551fb090702a65752fad..aba4cfb6d2e5dd728bd1edd8a3aad2c3afe70d02 100644 --- a/drivers/gpu/drm/msm/dp/dp_catalog.c +++ b/drivers/gpu/drm/msm/dp/dp_catalog.c @@ -703,7 +703,7 @@ static void dp_catalog_ctrl_state_ctrl(struct dp_catalog_ctrl *ctrl, u32 state) wmb(); } -static void dp_catalog_ctrl_config_ctrl(struct dp_catalog_ctrl *ctrl) +static void dp_catalog_ctrl_config_ctrl(struct dp_catalog_ctrl *ctrl, u8 ln_cnt) { struct dp_catalog_private *catalog; struct dp_io_data *io_data; @@ -717,6 +717,11 @@ static void dp_catalog_ctrl_config_ctrl(struct dp_catalog_ctrl *ctrl) catalog = dp_catalog_get_priv(ctrl); io_data = catalog->io.dp_link; + cfg = dp_read(catalog->exe_mode, io_data, DP_CONFIGURATION_CTRL); + cfg &= ~(BIT(4) | BIT(5)); + cfg |= (ln_cnt - 1) << 4; + dp_write(catalog->exe_mode, io_data, DP_CONFIGURATION_CTRL, cfg); + cfg = dp_read(catalog->exe_mode, io_data, DP_MAINLINK_CTRL); cfg |= 0x02000000; dp_write(catalog->exe_mode, io_data, DP_MAINLINK_CTRL, cfg); @@ -935,6 +940,11 @@ static void dp_catalog_panel_config_msa(struct dp_catalog_panel *panel, * always be within the range of a 32 bit unsigned int. */ mvid = (u32) mvid_calc; + + if (panel->widebus_en) { + mvid <<= 1; + nvid <<= 1; + } } else { io_data = catalog->io.dp_mmss_cc; @@ -952,6 +962,9 @@ static void dp_catalog_panel_config_msa(struct dp_catalog_panel *panel, pr_debug("rate = %d\n", rate); + if (panel->widebus_en) + mvid <<= 1; + if (link_rate_hbr2 == rate) nvid *= 2; @@ -1719,7 +1732,7 @@ static int dp_catalog_panel_timing_cfg(struct dp_catalog_panel *panel) { struct dp_catalog_private *catalog; struct dp_io_data *io_data; - u32 offset = 0; + u32 offset = 0, reg; if (!panel) { pr_err("invalid input\n"); @@ -1745,6 +1758,20 @@ static int dp_catalog_panel_timing_cfg(struct dp_catalog_panel *panel) DP_HSYNC_VSYNC_WIDTH_POLARITY + offset, panel->width_blanking); dp_write(catalog->exe_mode, io_data, DP_ACTIVE_HOR_VER + offset, panel->dp_active); + + if (panel->stream_id == DP_STREAM_0) + io_data = catalog->io.dp_p0; + else + io_data = catalog->io.dp_p1; + + reg = dp_read(catalog->exe_mode, io_data, MMSS_DP_INTF_CONFIG); + + if (panel->widebus_en) + reg |= BIT(4); + else + reg &= ~BIT(4); + + dp_write(catalog->exe_mode, io_data, MMSS_DP_INTF_CONFIG, reg); end: return 0; } diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h index 6b09595bdfb10e9f358e42750abf7bdf6ce4c51d..4fd440dacd3c9cd9107e97368394fe7442b14934 100644 --- a/drivers/gpu/drm/msm/dp/dp_catalog.h +++ b/drivers/gpu/drm/msm/dp/dp_catalog.h @@ -99,7 +99,7 @@ struct dp_catalog_ctrl { u32 isr5; void (*state_ctrl)(struct dp_catalog_ctrl *ctrl, u32 state); - void (*config_ctrl)(struct dp_catalog_ctrl *ctrl); + void (*config_ctrl)(struct dp_catalog_ctrl *ctrl, u8 ln_cnt); void (*lane_mapping)(struct dp_catalog_ctrl *ctrl, bool flipped, char *lane_map); void (*mainlink_ctrl)(struct dp_catalog_ctrl *ctrl, bool enable); @@ -197,6 +197,8 @@ struct dp_catalog_panel { enum dp_stream_id stream_id; + bool widebus_en; + int (*timing_cfg)(struct dp_catalog_panel *panel); void (*config_hdr)(struct dp_catalog_panel *panel, bool en); void (*tpg_config)(struct dp_catalog_panel *panel, bool enable); diff --git a/drivers/gpu/drm/msm/dp/dp_catalog_v200.c b/drivers/gpu/drm/msm/dp/dp_catalog_v200.c index eb116df448ea0a9e106e59ee7f07c31f0b512794..797528faaa493f9ae639b965343f92eac5cd0d5a 100644 --- a/drivers/gpu/drm/msm/dp/dp_catalog_v200.c +++ b/drivers/gpu/drm/msm/dp/dp_catalog_v200.c @@ -171,6 +171,11 @@ static void dp_catalog_panel_config_msa_v200(struct dp_catalog_panel *panel, * always be within the range of a 32 bit unsigned int. */ mvid = (u32) mvid_calc; + + if (panel->widebus_en) { + mvid <<= 1; + nvid <<= 1; + } } else { io_data = catalog->io->dp_mmss_cc; @@ -189,6 +194,9 @@ static void dp_catalog_panel_config_msa_v200(struct dp_catalog_panel *panel, pr_debug("rate = %d\n", rate); + if (panel->widebus_en) + mvid <<= 1; + if (link_rate_hbr2 == rate) nvid *= 2; diff --git a/drivers/gpu/drm/msm/dp/dp_catalog_v420.c b/drivers/gpu/drm/msm/dp/dp_catalog_v420.c index 5337835a3a2067fb46ba28cf2f2fa7f95485a3af..e5e2e19c17b496978a7efa22f2befa6e84a8accf 100644 --- a/drivers/gpu/drm/msm/dp/dp_catalog_v420.c +++ b/drivers/gpu/drm/msm/dp/dp_catalog_v420.c @@ -145,6 +145,11 @@ static void dp_catalog_panel_config_msa_v420(struct dp_catalog_panel *panel, * always be within the range of a 32 bit unsigned int. */ mvid = (u32) mvid_calc; + + if (panel->widebus_en) { + mvid <<= 1; + nvid <<= 1; + } } else { io_data = catalog->io->dp_mmss_cc; @@ -162,6 +167,9 @@ static void dp_catalog_panel_config_msa_v420(struct dp_catalog_panel *panel, pr_debug("rate = %d\n", rate); + if (panel->widebus_en) + mvid <<= 1; + if (link_rate_hbr2 == rate) nvid *= 2; diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index 487e8fa91f1cc9b36a26124b2c06489a79a886a2..ed4cd221073cc55b01f46c3bd01a188970c879bd 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -170,7 +170,8 @@ static void dp_ctrl_configure_source_link_params(struct dp_ctrl_private *ctrl, ctrl->catalog->lane_mapping(ctrl->catalog, ctrl->orientation, ctrl->parser->l_map); ctrl->catalog->mst_config(ctrl->catalog, ctrl->mst_mode); - ctrl->catalog->config_ctrl(ctrl->catalog); + ctrl->catalog->config_ctrl(ctrl->catalog, + ctrl->link->link_params.lane_count); ctrl->catalog->mainlink_ctrl(ctrl->catalog, true); } else { ctrl->catalog->mainlink_ctrl(ctrl->catalog, false); @@ -615,6 +616,9 @@ static int dp_ctrl_enable_stream_clocks(struct dp_ctrl_private *ctrl, struct dp_panel *dp_panel) { int ret = 0; + u32 pclk; + enum dp_pm_type clk_type; + char clk_name[32] = ""; ret = ctrl->power->set_pixel_clk_parent(ctrl->power, dp_panel->stream_id); @@ -623,26 +627,27 @@ static int dp_ctrl_enable_stream_clocks(struct dp_ctrl_private *ctrl, return ret; if (dp_panel->stream_id == DP_STREAM_0) { - dp_ctrl_set_clock_rate(ctrl, "strm0_pixel_clk", DP_STREAM0_PM, - dp_panel->pinfo.pixel_clk_khz); - - ret = ctrl->power->clk_enable(ctrl->power, DP_STREAM0_PM, true); - if (ret) { - pr_err("Unabled to start stream0 clocks\n"); - ret = -EINVAL; - } + clk_type = DP_STREAM0_PM; + strlcpy(clk_name, "strm0_pixel_clk", 32); } else if (dp_panel->stream_id == DP_STREAM_1) { - dp_ctrl_set_clock_rate(ctrl, "strm1_pixel_clk", DP_STREAM1_PM, - dp_panel->pinfo.pixel_clk_khz); - - ret = ctrl->power->clk_enable(ctrl->power, DP_STREAM1_PM, true); - if (ret) { - pr_err("Unabled to start stream1 clocks\n"); - ret = -EINVAL; - } + clk_type = DP_STREAM1_PM; + strlcpy(clk_name, "strm1_pixel_clk", 32); } else { pr_err("Invalid stream:%d for clk enable\n", dp_panel->stream_id); + return -EINVAL; + } + + pclk = dp_panel->pinfo.widebus_en ? + (dp_panel->pinfo.pixel_clk_khz >> 1) : + (dp_panel->pinfo.pixel_clk_khz); + + dp_ctrl_set_clock_rate(ctrl, clk_name, clk_type, pclk); + + ret = ctrl->power->clk_enable(ctrl->power, clk_type, true); + if (ret) { + pr_err("Unabled to start stream:%d clocks\n", + dp_panel->stream_id); ret = -EINVAL; } @@ -1002,15 +1007,15 @@ static int dp_ctrl_stream_on(struct dp_ctrl *dp_ctrl, struct dp_panel *panel) return rc; } + rc = panel->hw_cfg(panel, true); + if (rc) + return rc; + if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) { dp_ctrl_send_phy_test_pattern(ctrl); return 0; } - rc = panel->hw_cfg(panel, true); - if (rc) - return rc; - dp_ctrl_mst_stream_setup(ctrl, panel); dp_ctrl_send_video(ctrl); diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c index caa7dd1aacbe18bbc49f9057d7601d957e0386e6..9b56e611d78765ee03477459933ba2a9bc280c6f 100644 --- a/drivers/gpu/drm/msm/dp/dp_debug.c +++ b/drivers/gpu/drm/msm/dp/dp_debug.c @@ -74,13 +74,13 @@ static int dp_debug_get_dpcd_buf(struct dp_debug_private *debug) int rc = 0; if (!debug->dpcd) { - debug->dpcd = devm_kzalloc(debug->dev, SZ_16K, GFP_KERNEL); + debug->dpcd = devm_kzalloc(debug->dev, SZ_4K, GFP_KERNEL); if (!debug->dpcd) { rc = -ENOMEM; goto end; } - debug->dpcd_size = SZ_16K; + debug->dpcd_size = SZ_4K; } end: return rc; @@ -161,9 +161,7 @@ static ssize_t dp_debug_write_edid(struct file *file, edid = debug->edid; bail: kfree(buf); - - if (!debug->dp_debug.sim_mode) - debug->panel->set_edid(debug->panel, edid); + debug->panel->set_edid(debug->panel, edid); return rc; } @@ -178,7 +176,8 @@ static ssize_t dp_debug_write_dpcd(struct file *file, size_t size = 0, dpcd_buf_index = 0; ssize_t rc = count; char offset_ch[5]; - u32 offset; + u32 offset, data_len; + const u32 dp_receiver_cap_size = 16; if (!debug) return -ENODEV; @@ -188,6 +187,9 @@ static ssize_t dp_debug_write_dpcd(struct file *file, size = min_t(size_t, count, SZ_2K); + if (size <= char_to_nib) + goto bail; + buf = kzalloc(size, GFP_KERNEL); if (ZERO_OR_NULL_PTR(buf)) { rc = -ENOMEM; @@ -217,6 +219,7 @@ static ssize_t dp_debug_write_dpcd(struct file *file, size -= 4; dpcd_size = size / char_to_nib; + data_len = dpcd_size; buf_t = buf + 4; dpcd_buf_index = offset; @@ -242,10 +245,15 @@ static ssize_t dp_debug_write_dpcd(struct file *file, dpcd = debug->dpcd; bail: kfree(buf); - if (debug->dp_debug.sim_mode) - debug->aux->dpcd_updated(debug->aux); - else + + /* + * Reset panel's dpcd in case of any failure. Also, set the + * panel's dpcd only if a full dpcd is provided with offset as 0. + */ + if (!dpcd || (!offset && (data_len == dp_receiver_cap_size))) debug->panel->set_dpcd(debug->panel, dpcd); + else + debug->aux->dpcd_updated(debug->aux); return rc; } @@ -254,21 +262,41 @@ static ssize_t dp_debug_read_dpcd(struct file *file, char __user *user_buff, size_t count, loff_t *ppos) { struct dp_debug_private *debug = file->private_data; - char buf[SZ_8]; + char *buf; + int const buf_size = SZ_4K; + u32 offset = 0; u32 len = 0; - if (!debug) + if (!debug || !debug->aux || !debug->dpcd) return -ENODEV; if (*ppos) return 0; - len += snprintf(buf, SZ_8, "0x%x\n", debug->aux->reg); + buf = kzalloc(buf_size, GFP_KERNEL); + if (!buf) + return -ENOMEM; - if (copy_to_user(user_buff, buf, len)) - return -EFAULT; + len += snprintf(buf, buf_size, "0x%x", debug->aux->reg); - *ppos += len; + if (!debug->aux->read) { + while (1) { + if (debug->aux->reg + offset >= buf_size || + offset >= debug->aux->size) + break; + + len += snprintf(buf + len, buf_size - len, "0x%x", + debug->dpcd[debug->aux->reg + offset++]); + } + + if (debug->dp_debug.sim_mode && debug->aux->dpcd_updated) + debug->aux->dpcd_updated(debug->aux); + } + + if (!copy_to_user(user_buff, buf, len)) + *ppos += len; + + kfree(buf); return len; } @@ -352,7 +380,7 @@ static ssize_t dp_debug_write_edid_modes_mst(struct file *file, { struct dp_debug_private *debug = file->private_data; struct dp_mst_connector *mst_connector; - char buf[SZ_32]; + char buf[SZ_512]; char *read_buf; size_t len = 0; @@ -366,7 +394,7 @@ static ssize_t dp_debug_write_edid_modes_mst(struct file *file, if (*ppos) goto end; - len = min_t(size_t, count, SZ_32 - 1); + len = min_t(size_t, count, SZ_512 - 1); if (copy_from_user(buf, user_buff, len)) goto end; @@ -612,6 +640,35 @@ static ssize_t dp_debug_mst_sideband_mode_write(struct file *file, return len; } +static ssize_t dp_debug_widebus_mode_write(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char buf[SZ_8]; + size_t len = 0; + u32 widebus_mode = 0; + + if (!debug || !debug->parser) + return -ENODEV; + + if (*ppos) + return 0; + + len = min_t(size_t, count, SZ_8 - 1); + if (copy_from_user(buf, user_buff, len)) + return -EFAULT; + + buf[len] = '\0'; + + if (kstrtoint(buf, 10, &widebus_mode) != 0) + return -EINVAL; + + debug->parser->has_widebus = widebus_mode ? true : false; + pr_debug("widebus_enable: %d\n", widebus_mode); + + return len; +} + static ssize_t dp_debug_tpg_write(struct file *file, const char __user *user_buff, size_t count, loff_t *ppos) { @@ -1373,11 +1430,13 @@ static ssize_t dp_debug_write_sim(struct file *file, debug->aux->set_sim_mode(debug->aux, false, NULL, NULL); debug->dp_debug.sim_mode = false; + debug->panel->set_edid(debug->panel, 0); if (debug->edid) { devm_kfree(debug->dev, debug->edid); debug->edid = NULL; } + debug->panel->set_dpcd(debug->panel, 0); if (debug->dpcd) { devm_kfree(debug->dev, debug->dpcd); debug->dpcd = NULL; @@ -1593,6 +1652,11 @@ static const struct file_operations hdcp_fops = { .read = dp_debug_read_hdcp, }; +static const struct file_operations widebus_mode_fops = { + .open = simple_open, + .write = dp_debug_widebus_mode_write, +}; + static int dp_debug_init(struct dp_debug *dp_debug) { int rc = 0; @@ -1804,6 +1868,14 @@ static int dp_debug_init(struct dp_debug *dp_debug) goto error_remove_dir; } + file = debugfs_create_file("widebus_mode", 0644, dir, + debug, &widebus_mode_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + pr_err("[%s] debugfs widebus failed, rc=%d\n", + DEBUG_NAME, rc); + } + return 0; error_remove_dir: diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index ac98e216b4d171cb10b7ac76bcb35cf12503693d..0019622a5af3e5efcadf3382445df77c8c4a3c38 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -220,6 +220,31 @@ static void dp_display_update_hdcp_info(struct dp_display_private *dp) sde_hdcp_version(dp->link->hdcp_status.hdcp_version)); } +static void dp_display_check_source_hdcp_caps(struct dp_display_private *dp) +{ + int i; + struct dp_hdcp_dev *hdcp_dev = dp->hdcp.dev; + + if (dp->debug->hdcp_disabled) { + pr_debug("hdcp disabled\n"); + return; + } + + for (i = 0; i < HDCP_VERSION_MAX; i++) { + struct dp_hdcp_dev *dev = &hdcp_dev[i]; + struct sde_hdcp_ops *ops = dev->ops; + void *fd = dev->fd; + + if (!fd || !ops || (dp->hdcp.source_cap & dev->ver)) + continue; + + if (ops->feature_supported(fd)) + dp->hdcp.source_cap |= dev->ver; + } + + dp_display_update_hdcp_status(dp, false); +} + static void dp_display_hdcp_cb_work(struct work_struct *work) { struct dp_display_private *dp; @@ -238,6 +263,7 @@ static void dp_display_hdcp_cb_work(struct work_struct *work) status = &dp->link->hdcp_status; if (status->hdcp_state == HDCP_STATE_INACTIVE) { + dp_display_check_source_hdcp_caps(dp); dp_display_update_hdcp_info(dp); if (dp_display_is_hdcp_enabled(dp)) { @@ -304,37 +330,6 @@ static void dp_display_notify_hdcp_status_cb(void *ptr, mutex_unlock(&dp->session_lock); } -static void dp_display_check_source_hdcp_caps(struct dp_display_private *dp) -{ - int i; - struct dp_hdcp_dev *hdcp_dev = dp->hdcp.dev; - - if (dp->debug->hdcp_disabled) { - pr_debug("hdcp disabled\n"); - return; - } - - for (i = 0; i < HDCP_VERSION_MAX; i++) { - struct dp_hdcp_dev *dev = &hdcp_dev[i]; - struct sde_hdcp_ops *ops = dev->ops; - void *fd = dev->fd; - - if (!fd || !ops) - continue; - - if (ops->feature_supported(fd)) - dp->hdcp.source_cap |= dev->ver; - else - pr_warn("This device doesn't support %s\n", - sde_hdcp_version(dev->ver)); - } - - if (!dp->hdcp.source_cap) - dp->debug->hdcp_disabled = true; - - dp_display_update_hdcp_status(dp, false); -} - static void dp_display_deinitialize_hdcp(struct dp_display_private *dp) { if (!dp) { @@ -532,9 +527,6 @@ static void dp_display_post_open(struct dp_display *dp_display) return; } - dp_display_update_hdcp_status(dp, true); - dp_display_check_source_hdcp_caps(dp); - /* if cable is already connected, send notification */ if (dp->hpd->hpd_high) queue_delayed_work(dp->wq, &dp->connect_work, HZ * 10); @@ -603,10 +595,11 @@ static void dp_display_host_init(struct dp_display_private *dp) bool flip = false; bool reset; - if (dp->core_initialized) { - pr_debug("DP core already initialized\n"); + if (dp->core_initialized) return; - } + + if (!dp->debug->sim_mode && !dp->parser->no_aux_switch) + dp->aux->aux_switch(dp->aux, true, dp->hpd->orientation); if (dp->hpd->orientation == ORIENTATION_CC2) flip = true; @@ -618,38 +611,39 @@ static void dp_display_host_init(struct dp_display_private *dp) dp->aux->init(dp->aux, dp->parser->aux_cfg); enable_irq(dp->irq); dp->core_initialized = true; + + /* log this as it results from user action of cable connection */ + pr_info("[OK]\n"); } static void dp_display_host_deinit(struct dp_display_private *dp) { - if (!dp->core_initialized) { - pr_debug("DP core already off\n"); + if (!dp->core_initialized) return; - } if (dp->active_stream_cnt) { pr_debug("active stream present\n"); return; } + if (!dp->debug->sim_mode && !dp->parser->no_aux_switch) + dp->aux->aux_switch(dp->aux, false, ORIENTATION_NONE); + dp->aux->deinit(dp->aux); dp->ctrl->deinit(dp->ctrl); dp->power->deinit(dp->power); disable_irq(dp->irq); dp->core_initialized = false; dp->aux->state = 0; + + /* log this as it results from user action of cable dis-connection */ + pr_info("[OK]\n"); } static int dp_display_process_hpd_high(struct dp_display_private *dp) { int rc = 0; - if (!dp->debug->sim_mode && !dp->parser->no_aux_switch) { - rc = dp->aux->aux_switch(dp->aux, true, dp->hpd->orientation); - if (rc) - goto end; - } - dp->is_connected = true; dp->dp_display.max_pclk_khz = dp->parser->max_pclk_khz; @@ -727,10 +721,8 @@ static int dp_display_process_hpd_low(struct dp_display_private *dp) dp_panel = dp->active_panels[idx]; - if (dp_panel->audio_supported) { + if (dp_panel->audio_supported) dp_panel->audio->off(dp_panel->audio); - dp_panel->audio_supported = false; - } } mutex_unlock(&dp->session_lock); @@ -767,6 +759,8 @@ static int dp_display_usbpd_configure_cb(struct device *dev) goto end; } + dp_display_host_init(dp); + /* check for hpd high and framework ready */ if (dp->hpd->hpd_high && dp_display_framework_ready(dp)) queue_delayed_work(dp->wq, &dp->connect_work, 0); @@ -860,9 +854,6 @@ static int dp_display_usbpd_disconnect_cb(struct device *dev) cancel_work(&dp->attention_work); flush_workqueue(dp->wq); - if (!dp->debug->sim_mode && !dp->parser->no_aux_switch) - dp->aux->aux_switch(dp->aux, false, ORIENTATION_NONE); - dp_display_handle_disconnect(dp); /* Reset abort value to allow future connections */ @@ -981,7 +972,7 @@ static int dp_display_usbpd_attention_cb(struct device *dev) return -ENODEV; } - DP_MST_DEBUG("mst: hpd_irq:%d, hpd_high:%d, power_on:%d\n", + pr_debug("hpd_irq:%d, hpd_high:%d, power_on:%d\n", dp->hpd->hpd_irq, dp->hpd->hpd_high, dp->power_on); @@ -1082,6 +1073,8 @@ static int dp_init_sub_modules(struct dp_display_private *dp) goto error_catalog; } + g_dp_display->is_mst_supported = dp->parser->has_mst; + dp->catalog = dp_catalog_get(dev, dp->parser); if (IS_ERR(dp->catalog)) { rc = PTR_ERR(dp->catalog); @@ -1132,6 +1125,7 @@ static int dp_init_sub_modules(struct dp_display_private *dp) panel_in.link = dp->link; panel_in.connector = dp->dp_display.base_connector; panel_in.base_panel = NULL; + panel_in.parser = dp->parser; dp->panel = dp_panel_get(&panel_in); if (IS_ERR(dp->panel)) { @@ -1199,6 +1193,7 @@ static int dp_init_sub_modules(struct dp_display_private *dp) } dp->debug->hdcp_disabled = hdcp_disabled; + dp_display_update_hdcp_status(dp, true); return rc; error_debug: @@ -1428,7 +1423,6 @@ static int dp_display_post_enable(struct dp_display *dp_display, void *panel) { struct dp_display_private *dp; struct dp_panel *dp_panel; - struct edid *edid; if (!dp_display || !panel) { pr_err("invalid input\n"); @@ -1455,9 +1449,6 @@ static int dp_display_post_enable(struct dp_display *dp_display, void *panel) dp_display_stream_post_enable(dp, dp_panel); - edid = dp_panel->edid_ctrl->edid; - dp_panel->audio_supported = drm_detect_monitor_audio(edid); - if (dp_panel->audio_supported) { dp_panel->audio->bw_code = dp->link->link_params.bw_code; dp_panel->audio->lane_count = dp->link->link_params.lane_count; @@ -1568,6 +1559,9 @@ static int dp_display_disable(struct dp_display *dp_display, void *panel) } dp->power_on = false; + + /* log this as it results from user action of cable dis-connection */ + pr_info("[OK]\n"); end: dp_panel->deinit(dp_panel); mutex_unlock(&dp->session_lock); @@ -1974,6 +1968,7 @@ static int dp_display_mst_connector_install(struct dp_display *dp_display, panel_in.link = dp->link; panel_in.connector = connector; panel_in.base_panel = dp->panel; + panel_in.parser = dp->parser; dp_panel = dp_panel_get(&panel_in); if (IS_ERR(dp_panel)) { @@ -1999,6 +1994,12 @@ static int dp_display_mst_connector_install(struct dp_display *dp_display, mst_connector = kmalloc(sizeof(struct dp_mst_connector), GFP_KERNEL); + if (!mst_connector) { + mutex_unlock(&dp->debug->dp_mst_connector_list.lock); + mutex_unlock(&dp->session_lock); + return -ENOMEM; + } + mst_connector->debug_en = false; mst_connector->conn = connector; mst_connector->con_id = connector->base.id; @@ -2055,7 +2056,7 @@ static int dp_display_mst_connector_uninstall(struct dp_display *dp_display, list_for_each_entry_safe(con_to_remove, temp_con, &dp->debug->dp_mst_connector_list.list, list) { - if (con_to_remove->con_id == connector->base.id) { + if (con_to_remove->conn == connector) { list_del(&con_to_remove->list); kfree(con_to_remove); } @@ -2229,7 +2230,10 @@ int dp_display_get_num_of_displays(void) int dp_display_get_num_of_streams(void) { - return 2; + if (g_dp_display->is_mst_supported) + return DP_STREAM_MAX; + + return 0; } static int dp_display_remove(struct platform_device *pdev) diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h index 512778c747950199c66c2d5fba977cdbe9853d83..090155e12b93bb24bb8768742a120dd881d9e45b 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.h +++ b/drivers/gpu/drm/msm/dp/dp_display.h @@ -62,6 +62,7 @@ struct dp_display { struct drm_connector *base_connector; void *base_dp_panel; bool is_sst_connected; + bool is_mst_supported; u32 max_pclk_khz; void *dp_mst_prv_info; diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c index 563b0e0f7ba716658574f0655c8f6eb6d7bf92dd..9b004fd1b9c08bda8112a173eac24f1636f0b850 100644 --- a/drivers/gpu/drm/msm/dp/dp_drm.c +++ b/drivers/gpu/drm/msm/dp/dp_drm.c @@ -372,14 +372,19 @@ int dp_connector_get_mode_info(struct drm_connector *connector, const u32 single_intf = 1; const u32 no_enc = 0; struct msm_display_topology *topology; + struct sde_connector *sde_conn; + struct dp_panel *dp_panel; - if (!drm_mode || !mode_info || !max_mixer_width) { + if (!drm_mode || !mode_info || !max_mixer_width || !connector) { pr_err("invalid params\n"); return -EINVAL; } memset(mode_info, 0, sizeof(*mode_info)); + sde_conn = to_sde_connector(connector); + dp_panel = sde_conn->drv_panel; + topology = &mode_info->topology; topology->num_lm = (max_mixer_width <= drm_mode->hdisplay) ? dual_lm : single_lm; @@ -389,6 +394,8 @@ int dp_connector_get_mode_info(struct drm_connector *connector, mode_info->frame_rate = drm_mode->vrefresh; mode_info->vtotal = drm_mode->vtotal; + mode_info->wide_bus_en = dp_panel->widebus_en; + return 0; } diff --git a/drivers/gpu/drm/msm/dp/dp_gpio_hpd.c b/drivers/gpu/drm/msm/dp/dp_gpio_hpd.c index 5fb18412f4bf2f5100ec7ffb9038f2419903dee2..81e833b0f213b3be5af3d9645284e5aa04f4f873 100644 --- a/drivers/gpu/drm/msm/dp/dp_gpio_hpd.c +++ b/drivers/gpu/drm/msm/dp/dp_gpio_hpd.c @@ -193,6 +193,7 @@ struct dp_hpd *dp_gpio_hpd_get(struct device *dev, int rc = 0; const char *hpd_gpio_name = "qcom,dp-hpd-gpio"; struct dp_gpio_hpd_private *gpio_hpd; + struct dp_pinctrl pinctrl = {0}; int edge; if (!dev || !cb) { @@ -207,6 +208,20 @@ struct dp_hpd *dp_gpio_hpd_get(struct device *dev, goto error; } + pinctrl.pin = devm_pinctrl_get(dev); + if (!IS_ERR_OR_NULL(pinctrl.pin)) { + pinctrl.state_hpd_active = pinctrl_lookup_state(pinctrl.pin, + "mdss_dp_hpd_active"); + if (!IS_ERR_OR_NULL(pinctrl.state_hpd_active)) { + rc = pinctrl_select_state(pinctrl.pin, + pinctrl.state_hpd_active); + if (rc) { + pr_err("failed to set hpd active state\n"); + goto gpio_error; + } + } + } + gpio_hpd->gpio_cfg.gpio = of_get_named_gpio(dev->of_node, hpd_gpio_name, 0); if (!gpio_is_valid(gpio_hpd->gpio_cfg.gpio)) { diff --git a/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c b/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c index 07efbf14fd99a5d16475ee29bd8c99b9c023eb43..d548a4583ca5ebd01388c41ccf8872bc45b01767 100644 --- a/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c +++ b/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c @@ -478,10 +478,6 @@ static void dp_hdcp2p2_send_msg_work(struct kthread_work *work) goto exit; } - print_hex_dump(KERN_DEBUG, ": ", - DUMP_PREFIX_NONE, 16, 1, ctrl->response.data, - ctrl->response.length, false); - mutex_lock(&ctrl->msg_lock); rc = dp_hdcp2p2_aux_write_message(ctrl, ctrl->response.data, diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c index 05629dd4942185044859b55ca28e762427bef2d9..225a8ebb95a773a929e8bf010513d7eb74d9ed78 100644 --- a/drivers/gpu/drm/msm/dp/dp_link.c +++ b/drivers/gpu/drm/msm/dp/dp_link.c @@ -788,12 +788,8 @@ static int dp_link_parse_request(struct dp_link_private *link) data = bp; - pr_debug("device service irq vector = 0x%x\n", data); - - if (!(data & DP_AUTOMATED_TEST_REQUEST)) { - pr_debug("no test requested\n"); + if (!(data & DP_AUTOMATED_TEST_REQUEST)) return 0; - } /** * Read the link request byte (Byte 0x218) to determine what type @@ -814,7 +810,6 @@ static int dp_link_parse_request(struct dp_link_private *link) goto end; } - pr_debug("%s (0x%x) requested\n", dp_link_get_test_name(data), data); link->request.test_requested = data; if (link->request.test_requested == DP_TEST_LINK_PHY_TEST_PATTERN) { @@ -1286,8 +1281,6 @@ static int dp_link_process_request(struct dp_link *dp_link) link = container_of(dp_link, struct dp_link_private, dp_link); - pr_debug("start\n"); - dp_link_reset_data(link); dp_link_parse_sink_status_field(link); @@ -1333,9 +1326,18 @@ static int dp_link_process_request(struct dp_link *dp_link) goto exit; } - pr_debug("done\n"); -exit: + pr_debug("no test requested\n"); return ret; +exit: + /* + * log this as it can be a use initiated action to run a DP CTS + * test or in normal cases, sink has encountered a problem and + * and want source to redo some part of initialization which can + * be helpful in debugging. + */ + pr_info("test requested: %s\n", + dp_link_get_test_name(dp_link->sink_request)); + return 0; } static int dp_link_get_colorimetry_config(struct dp_link *dp_link) @@ -1376,6 +1378,7 @@ static int dp_link_adjust_levels(struct dp_link *dp_link, u8 *link_status) int max = 0; u8 data; struct dp_link_private *link; + u8 buf[8] = {0}, offset = 0; if (!dp_link) { pr_err("invalid input\n"); @@ -1387,49 +1390,52 @@ static int dp_link_adjust_levels(struct dp_link *dp_link, u8 *link_status) /* use the max level across lanes */ for (i = 0; i < dp_link->link_params.lane_count; i++) { data = drm_dp_get_adjust_request_voltage(link_status, i); - pr_debug("lane=%d req_voltage_swing=%d\n", i, data); + data >>= DP_TRAIN_VOLTAGE_SWING_SHIFT; + + offset = i * 2; + if (offset < sizeof(buf)) + buf[offset] = data; + if (max < data) max = data; } - dp_link->phy_params.v_level = max >> DP_TRAIN_VOLTAGE_SWING_SHIFT; + dp_link->phy_params.v_level = max; /* use the max level across lanes */ max = 0; for (i = 0; i < dp_link->link_params.lane_count; i++) { data = drm_dp_get_adjust_request_pre_emphasis(link_status, i); - pr_debug("lane=%d req_pre_emphasis=%d\n", i, data); + data >>= DP_TRAIN_PRE_EMPHASIS_SHIFT; + + offset = (i * 2) + 1; + if (offset < sizeof(buf)) + buf[offset] = data; + if (max < data) max = data; } - dp_link->phy_params.p_level = max >> DP_TRAIN_PRE_EMPHASIS_SHIFT; + dp_link->phy_params.p_level = max; + + print_hex_dump(KERN_DEBUG, "[drm-dp] Req (VxPx): ", + DUMP_PREFIX_NONE, 8, 2, buf, sizeof(buf), false); /** * Adjust the voltage swing and pre-emphasis level combination to within * the allowable range. */ - if (dp_link->phy_params.v_level > DP_LINK_VOLTAGE_MAX) { - pr_debug("Requested vSwingLevel=%d, change to %d\n", - dp_link->phy_params.v_level, DP_LINK_VOLTAGE_MAX); + if (dp_link->phy_params.v_level > DP_LINK_VOLTAGE_MAX) dp_link->phy_params.v_level = DP_LINK_VOLTAGE_MAX; - } - if (dp_link->phy_params.p_level > DP_LINK_PRE_EMPHASIS_MAX) { - pr_debug("Requested preEmphasisLevel=%d, change to %d\n", - dp_link->phy_params.p_level, DP_LINK_PRE_EMPHASIS_MAX); + if (dp_link->phy_params.p_level > DP_LINK_PRE_EMPHASIS_MAX) dp_link->phy_params.p_level = DP_LINK_PRE_EMPHASIS_MAX; - } if ((dp_link->phy_params.p_level > DP_LINK_PRE_EMPHASIS_LEVEL_1) - && (dp_link->phy_params.v_level == DP_LINK_VOLTAGE_LEVEL_2)) { - pr_debug("Requested preEmphasisLevel=%d, change to %d\n", - dp_link->phy_params.p_level, - DP_LINK_PRE_EMPHASIS_LEVEL_1); + && (dp_link->phy_params.v_level == DP_LINK_VOLTAGE_LEVEL_2)) dp_link->phy_params.p_level = DP_LINK_PRE_EMPHASIS_LEVEL_1; - } - pr_debug("adjusted: v_level=%d, p_level=%d\n", + pr_debug("Set (VxPx): %x%x\n", dp_link->phy_params.v_level, dp_link->phy_params.p_level); return 0; diff --git a/drivers/gpu/drm/msm/dp/dp_link.h b/drivers/gpu/drm/msm/dp/dp_link.h index d14b88155444887fcd19283259b33fd56ab9e949..c4fa00577f8bc44988a6510774e1a5f26aea6b81 100644 --- a/drivers/gpu/drm/msm/dp/dp_link.h +++ b/drivers/gpu/drm/msm/dp/dp_link.h @@ -101,6 +101,10 @@ static inline char *dp_link_get_test_name(u32 test_requested) return DP_LINK_ENUM_STR(DP_TEST_LINK_PHY_TEST_PATTERN); case DP_TEST_LINK_AUDIO_PATTERN: return DP_LINK_ENUM_STR(DP_TEST_LINK_AUDIO_PATTERN); + case DS_PORT_STATUS_CHANGED: + return DP_LINK_ENUM_STR(DS_PORT_STATUS_CHANGED); + case DP_LINK_STATUS_UPDATED: + return DP_LINK_ENUM_STR(DP_LINK_STATUS_UPDATED); default: return "unknown"; } diff --git a/drivers/gpu/drm/msm/dp/dp_mst_drm.c b/drivers/gpu/drm/msm/dp/dp_mst_drm.c index e23c4a1fc3bb5186fdf3528e19267fddb7bfb945..133d4a98fdecafda0e6ac00eb88216762b323379 100644 --- a/drivers/gpu/drm/msm/dp/dp_mst_drm.c +++ b/drivers/gpu/drm/msm/dp/dp_mst_drm.c @@ -34,6 +34,7 @@ #define MAX_DP_MST_DRM_ENCODERS 2 #define MAX_DP_MST_DRM_BRIDGES 2 #define DP_MST_SIM_MAX_PORTS 2 +#define HPD_STRING_SIZE 30 struct dp_drm_mst_fw_helper_ops { int (*calc_pbn_mode)(int clock, int bpp); @@ -1330,6 +1331,27 @@ static void dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr) DP_MST_DEBUG("mst hot plug event\n"); } +static void dp_mst_hpd_event_notify(struct dp_mst_private *mst, bool hpd_status) +{ + struct drm_device *dev = mst->dp_display->drm_dev; + char event_string[] = "MST_HOTPLUG=1"; + char status[HPD_STRING_SIZE]; + char *envp[3]; + + if (hpd_status) + snprintf(status, HPD_STRING_SIZE, "status=connected"); + else + snprintf(status, HPD_STRING_SIZE, "status=disconnected"); + + envp[0] = event_string; + envp[1] = status; + envp[2] = NULL; + + kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, envp); + + DP_MST_DEBUG("%s finished\n", __func__); +} + /* DP Driver Callback OPs */ static void dp_mst_display_hpd(void *dp_display, bool hpd_status, @@ -1357,6 +1379,8 @@ static void dp_mst_display_hpd(void *dp_display, bool hpd_status, rc = mst->mst_fw_cbs->topology_mgr_set_mst(&mst->mst_mgr, hpd_status); + dp_mst_hpd_event_notify(mst, hpd_status); + DP_MST_DEBUG("mst display hpd:%d, rc:%d\n", hpd_status, rc); DP_MST_DEBUG("exit:\n"); diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c index 34283a3334a9aaea170bcf3234dedf3bff9c950b..0e3a5a17876f634d24f17b8fa5fbf6d93e74fe3d 100644 --- a/drivers/gpu/drm/msm/dp/dp_panel.c +++ b/drivers/gpu/drm/msm/dp/dp_panel.c @@ -15,6 +15,7 @@ #define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__ #include "dp_panel.h" +#include #define DP_KHZ_TO_HZ 1000 #define DP_PANEL_DEFAULT_BPP 24 @@ -25,20 +26,6 @@ #define VSC_EXT_VESA_SDP_SUPPORTED BIT(4) #define VSC_EXT_VESA_SDP_CHAINING_SUPPORTED BIT(5) -struct dp_vc_tu_mapping_table { - u32 vic; - u8 lanes; - u8 lrate; /* DP_LINK_RATE -> 162(6), 270(10), 540(20), 810 (30) */ - u8 bpp; - u32 valid_boundary_link; - u32 delay_start_link; - bool boundary_moderation_en; - u32 valid_lower_boundary_link; - u32 upper_boundary_count; - u32 lower_boundary_count; - u32 tu_size_minus1; -}; - enum dp_panel_hdr_pixel_encoding { RGB, YCbCr444, @@ -81,6 +68,7 @@ struct dp_panel_private { struct dp_panel dp_panel; struct dp_aux *aux; struct dp_link *link; + struct dp_parser *parser; struct dp_catalog_panel *catalog; bool custom_edid; bool custom_dpcd; @@ -119,504 +107,700 @@ static const u8 vendor_name[8] = {81, 117, 97, 108, 99, 111, 109, 109}; static const u8 product_desc[16] = {83, 110, 97, 112, 100, 114, 97, 103, 111, 110, 0, 0, 0, 0, 0, 0}; -static void dp_panel_get_extra_req_bytes(u64 result_valid, - int valid_bdary_link, - u64 value1, u64 value2, - bool *negative, u64 *result, - u64 compare) -{ - *negative = false; - if (result_valid >= compare) { - if (valid_bdary_link - >= compare) - *result = value1 + value2; - else { - if (value1 < value2) - *negative = true; - *result = (value1 >= value2) ? - (value1 - value2) : (value2 - value1); - } - } else { - if (valid_bdary_link - >= compare) { - if (value1 >= value2) - *negative = true; - *result = (value1 >= value2) ? - (value1 - value2) : (value2 - value1); - } else { - *result = value1 + value2; - *negative = true; - } - } -} - -static u64 roundup_u64(u64 x, u64 y) -{ - x += (y - 1); - return (div64_ul(x, y) * y); -} - -static u64 rounddown_u64(u64 x, u64 y) -{ - u64 rem; - - div64_u64_rem(x, y, &rem); - return (x - rem); -} +struct tu_algo_data { + s64 lclk_fp; + s64 pclk_fp; + s64 lwidth; + s64 hbp_relative_to_pclk; + int nlanes; + int bpp; + int pixelEnc; + int dsc_en; + int async_en; + int bpc; + + uint delay_start_link_extra_pixclk; + int extra_buffer_margin; + s64 ratio_fp; + s64 original_ratio_fp; + + s64 err_fp; + s64 n_err_fp; + s64 n_n_err_fp; + int tu_size; + int tu_size_desired; + int tu_size_minus1; -static void dp_panel_calc_tu_parameters(struct dp_panel *dp_panel, - struct dp_vc_tu_mapping_table *tu_table) -{ - u32 const multiplier = 1000000; - u64 pclk, lclk; - u8 bpp, ln_cnt; - int run_idx = 0; - u32 lwidth, h_blank; - u32 fifo_empty = 0; - u32 ratio_scale = 1001; - u64 temp, ratio, original_ratio; - u64 temp2, reminder; - u64 temp3, temp4, result = 0; - - u64 err = multiplier; - u64 n_err = 0, n_n_err = 0; - bool n_err_neg, nn_err_neg; - u8 hblank_margin = 16; - - u8 tu_size, tu_size_desired = 0, tu_size_minus1; int valid_boundary_link; - u32 resulting_valid; - u64 total_valid; - u64 effective_valid; - u64 effective_valid_recorded; + s64 resulting_valid_fp; + s64 total_valid_fp; + s64 effective_valid_fp; + s64 effective_valid_recorded_fp; int n_tus; int n_tus_per_lane; int paired_tus; int remainder_tus; - int remainder_tus_upper, remainder_tus_lower; + int remainder_tus_upper; + int remainder_tus_lower; int extra_bytes; int filler_size; int delay_start_link; - int boundary_moderation_en = 0; - int upper_bdry_cnt = 0; - int lower_bdry_cnt = 0; - int i_upper_bdry_cnt = 0; - int i_lower_bdry_cnt = 0; - int valid_lower_boundary_link = 0; - int even_distribution_bf = 0; - int even_distribution_legacy = 0; - int even_distribution = 0; - int min_hblank = 0; + int extra_pclk_cycles; - u8 extra_pclk_cycle_delay = 4; int extra_pclk_cycles_in_link_clk; - u64 ratio_by_tu; - u64 average_valid2; - u64 extra_buffer_margin; + s64 ratio_by_tu_fp; + s64 average_valid2_fp; int new_valid_boundary_link; + int remainder_symbols_exist; + int n_symbols; + s64 n_remainder_symbols_per_lane_fp; + s64 last_partial_tu_fp; + s64 TU_ratio_err_fp; - u64 resulting_valid_tmp; - u64 ratio_by_tu_tmp; - int n_tus_tmp; + int n_tus_incl_last_incomplete_tu; int extra_pclk_cycles_tmp; - int extra_pclk_cycles_in_lclk_tmp; - int extra_req_bytes_new_tmp; + int extra_pclk_cycles_in_link_clk_tmp; + int extra_required_bytes_new_tmp; int filler_size_tmp; int lower_filler_size_tmp; int delay_start_link_tmp; - int min_hblank_tmp = 0; - bool extra_req_bytes_is_neg = false; - struct dp_panel_info *pinfo = &dp_panel->pinfo; - u8 dp_brute_force = 1; - u64 brute_force_threshold = 10; - u64 diff_abs; + bool boundary_moderation_en; + int boundary_mod_lower_err; + int upper_boundary_count; + int lower_boundary_count; + int i_upper_boundary_count; + int i_lower_boundary_count; + int valid_lower_boundary_link; + int even_distribution_BF; + int even_distribution_legacy; + int even_distribution; + int min_hblank_violated; + s64 delay_start_time_fp; + s64 hbp_time_fp; + s64 hactive_time_fp; + s64 diff_abs_fp; + + s64 ratio; +}; - struct dp_panel_private *panel; +static int _tu_param_compare(s64 a, s64 b) +{ + u32 a_int, a_frac; + u32 b_int, b_frac; - panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + if (a == b) + return 0; - ln_cnt = panel->link->link_params.lane_count; + a_int = (a >> 32) & 0x7FFFFFFF; + a_frac = a & 0xFFFFFFFF; - bpp = pinfo->bpp; - lwidth = pinfo->h_active; - h_blank = pinfo->h_back_porch + pinfo->h_front_porch + - pinfo->h_sync_width; - pclk = pinfo->pixel_clk_khz * 1000; - - boundary_moderation_en = 0; - upper_bdry_cnt = 0; - lower_bdry_cnt = 0; - i_upper_bdry_cnt = 0; - i_lower_bdry_cnt = 0; - valid_lower_boundary_link = 0; - even_distribution_bf = 0; - even_distribution_legacy = 0; - even_distribution = 0; - min_hblank = 0; - - lclk = drm_dp_bw_code_to_link_rate( - panel->link->link_params.bw_code) * DP_KHZ_TO_HZ; - - pr_debug("pclk=%lld, active_width=%d, h_blank=%d\n", - pclk, lwidth, h_blank); - pr_debug("lclk = %lld, ln_cnt = %d\n", lclk, ln_cnt); - ratio = div64_u64_rem(pclk * bpp * multiplier, - 8 * ln_cnt * lclk, &reminder); - ratio = div64_u64((pclk * bpp * multiplier), (8 * ln_cnt * lclk)); - original_ratio = ratio; - - extra_buffer_margin = roundup_u64(div64_u64(extra_pclk_cycle_delay - * lclk * multiplier, pclk), multiplier); - extra_buffer_margin = div64_u64(extra_buffer_margin, multiplier); - - /* To deal with cases where lines are not distributable */ - if (((lwidth % ln_cnt) != 0) && ratio < multiplier) { - ratio = ratio * ratio_scale; - ratio = ratio < (1000 * multiplier) - ? ratio : (1000 * multiplier); + b_int = (b >> 32) & 0x7FFFFFFF; + b_frac = b & 0xFFFFFFFF; + + if (a_int > b_int) + return 1; + else if (a_int < b_int) + return 2; + else if (a_frac > b_frac) + return 1; + else + return 2; +} + +static void _tu_valid_boundary_calc(struct tu_algo_data *tu) +{ + s64 temp1_fp, temp2_fp, temp, temp1, temp2; + int compare_result_1, compare_result_2, compare_result_3; + + temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1); + temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp); + + tu->new_valid_boundary_link = drm_fixp2int_ceil(temp2_fp); + + temp = (tu->i_upper_boundary_count * + tu->new_valid_boundary_link + + tu->i_lower_boundary_count * + (tu->new_valid_boundary_link-1)); + tu->average_valid2_fp = drm_fixp_from_fraction(temp, + (tu->i_upper_boundary_count + + tu->i_lower_boundary_count)); + + temp1_fp = drm_fixp_from_fraction(tu->bpp, 8); + temp2_fp = drm_fixp_from_fraction(tu->lwidth, 1); + temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp); + temp2_fp = drm_fixp_div(temp1_fp, tu->average_valid2_fp); + tu->n_tus = drm_fixp2int(temp2_fp); + + temp1_fp = drm_fixp_from_fraction(tu->n_tus, 1); + temp2_fp = drm_fixp_mul(temp1_fp, tu->average_valid2_fp); + temp1_fp = drm_fixp_from_fraction(tu->n_symbols, 1); + temp2_fp = temp1_fp - temp2_fp; + temp1_fp = drm_fixp_from_fraction(tu->nlanes, 1); + temp2_fp = drm_fixp_div(temp2_fp, temp1_fp); + tu->n_remainder_symbols_per_lane_fp = temp2_fp; + + temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1); + tu->last_partial_tu_fp = + drm_fixp_div(tu->n_remainder_symbols_per_lane_fp, + temp1_fp); + + if (tu->n_remainder_symbols_per_lane_fp != 0) + tu->remainder_symbols_exist = 1; + else + tu->remainder_symbols_exist = 0; + + temp1_fp = drm_fixp_from_fraction(tu->n_tus, tu->nlanes); + tu->n_tus_per_lane = drm_fixp2int(temp1_fp); + + tu->paired_tus = (int)((tu->n_tus_per_lane) / + (tu->i_upper_boundary_count + + tu->i_lower_boundary_count)); + + tu->remainder_tus = tu->n_tus_per_lane - tu->paired_tus * + (tu->i_upper_boundary_count + + tu->i_lower_boundary_count); + + if ((tu->remainder_tus - tu->i_upper_boundary_count) > 0) { + tu->remainder_tus_upper = tu->i_upper_boundary_count; + tu->remainder_tus_lower = tu->remainder_tus - + tu->i_upper_boundary_count; + } else { + tu->remainder_tus_upper = tu->remainder_tus; + tu->remainder_tus_lower = 0; + } + + temp = tu->paired_tus * (tu->i_upper_boundary_count * + tu->new_valid_boundary_link + + tu->i_lower_boundary_count * + (tu->new_valid_boundary_link - 1)) + + (tu->remainder_tus_upper * + tu->new_valid_boundary_link) + + (tu->remainder_tus_lower * + (tu->new_valid_boundary_link - 1)); + tu->total_valid_fp = drm_fixp_from_fraction(temp, 1); + + if (tu->remainder_symbols_exist) { + temp1_fp = tu->total_valid_fp + + tu->n_remainder_symbols_per_lane_fp; + temp2_fp = drm_fixp_from_fraction(tu->n_tus_per_lane, 1); + temp2_fp = temp2_fp + tu->last_partial_tu_fp; + temp1_fp = drm_fixp_div(temp1_fp, temp2_fp); + } else { + temp2_fp = drm_fixp_from_fraction(tu->n_tus_per_lane, 1); + temp1_fp = drm_fixp_div(tu->total_valid_fp, temp2_fp); + } + tu->effective_valid_fp = temp1_fp; + + temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1); + temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp); + tu->n_n_err_fp = tu->effective_valid_fp - temp2_fp; + + temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1); + temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp); + tu->n_err_fp = tu->average_valid2_fp - temp2_fp; + + tu->even_distribution = tu->n_tus % tu->nlanes == 0 ? 1 : 0; + + temp1_fp = drm_fixp_from_fraction(tu->bpp, 8); + temp2_fp = drm_fixp_from_fraction(tu->lwidth, 1); + temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp); + temp2_fp = drm_fixp_div(temp1_fp, tu->average_valid2_fp); + + if (temp2_fp) + tu->n_tus_incl_last_incomplete_tu = drm_fixp2int_ceil(temp2_fp); + else + tu->n_tus_incl_last_incomplete_tu = 0; + + temp1 = 0; + temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1); + temp2_fp = drm_fixp_mul(tu->original_ratio_fp, temp1_fp); + temp1_fp = tu->average_valid2_fp - temp2_fp; + temp2_fp = drm_fixp_from_fraction(tu->n_tus_incl_last_incomplete_tu, 1); + temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp); + + if (temp1_fp) + temp1 = drm_fixp2int_ceil(temp1_fp); + + temp = tu->i_upper_boundary_count * tu->nlanes; + temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1); + temp2_fp = drm_fixp_mul(tu->original_ratio_fp, temp1_fp); + temp1_fp = drm_fixp_from_fraction(tu->new_valid_boundary_link, 1); + temp2_fp = temp1_fp - temp2_fp; + temp1_fp = drm_fixp_from_fraction(temp, 1); + temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp); + + if (temp2_fp) + temp2 = drm_fixp2int_ceil(temp2_fp); + else + temp2 = 0; + tu->extra_required_bytes_new_tmp = (int)(temp1 + temp2); + + temp1_fp = drm_fixp_from_fraction(8, tu->bpp); + temp2_fp = drm_fixp_from_fraction( + tu->extra_required_bytes_new_tmp, 1); + temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp); + + if (temp1_fp) + tu->extra_pclk_cycles_tmp = drm_fixp2int_ceil(temp1_fp); + else + tu->extra_pclk_cycles_tmp = 0; + + temp1_fp = drm_fixp_from_fraction(tu->extra_pclk_cycles_tmp, 1); + temp2_fp = drm_fixp_div(tu->lclk_fp, tu->pclk_fp); + temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp); + + if (temp1_fp) + tu->extra_pclk_cycles_in_link_clk_tmp = + drm_fixp2int_ceil(temp1_fp); + else + tu->extra_pclk_cycles_in_link_clk_tmp = 0; + + tu->filler_size_tmp = tu->tu_size - tu->new_valid_boundary_link; + + tu->lower_filler_size_tmp = tu->filler_size_tmp + 1; + + tu->delay_start_link_tmp = tu->extra_pclk_cycles_in_link_clk_tmp + + tu->lower_filler_size_tmp + + tu->extra_buffer_margin; + + temp1_fp = drm_fixp_from_fraction(tu->delay_start_link_tmp, 1); + tu->delay_start_time_fp = drm_fixp_div(temp1_fp, tu->lclk_fp); + + compare_result_1 = _tu_param_compare(tu->n_n_err_fp, tu->diff_abs_fp); + if (compare_result_1 == 2) + compare_result_1 = 1; + else + compare_result_1 = 0; + + compare_result_2 = _tu_param_compare(tu->n_n_err_fp, tu->err_fp); + if (compare_result_2 == 2) + compare_result_2 = 1; + else + compare_result_2 = 0; + + compare_result_3 = _tu_param_compare(tu->hbp_time_fp, + tu->delay_start_time_fp); + if (compare_result_3 == 2) + compare_result_3 = 0; + else + compare_result_3 = 1; + + if (((tu->even_distribution == 1) || + ((tu->even_distribution_BF == 0) && + (tu->even_distribution_legacy == 0))) && + tu->n_err_fp >= 0 && tu->n_n_err_fp >= 0 && + compare_result_2 && + (compare_result_1 || (tu->min_hblank_violated == 1)) && + (tu->new_valid_boundary_link - 1) > 0 && + compare_result_3 && + (tu->delay_start_link_tmp <= 1023)) { + tu->upper_boundary_count = tu->i_upper_boundary_count; + tu->lower_boundary_count = tu->i_lower_boundary_count; + tu->err_fp = tu->n_n_err_fp; + tu->boundary_moderation_en = true; + tu->tu_size_desired = tu->tu_size; + tu->valid_boundary_link = tu->new_valid_boundary_link; + tu->effective_valid_recorded_fp = tu->effective_valid_fp; + tu->even_distribution_BF = 1; + tu->delay_start_link = tu->delay_start_link_tmp; + } else if (tu->boundary_mod_lower_err == 0) { + compare_result_1 = _tu_param_compare(tu->n_n_err_fp, + tu->diff_abs_fp); + if (compare_result_1 == 2) + tu->boundary_mod_lower_err = 1; } - pr_debug("ratio = %lld\n", ratio); +} - for (tu_size = 32; tu_size <= 64; tu_size++) { - temp = ratio * tu_size; - temp2 = ((temp / multiplier) + 1) * multiplier; - n_err = roundup_u64(temp, multiplier) - temp; +static void _dp_panel_calc_tu(struct dp_tu_calc_input *in, + struct dp_vc_tu_mapping_table *tu_table) +{ + struct tu_algo_data tu; + int compare_result_1, compare_result_2; + u64 temp = 0; + s64 temp_fp = 0, temp1_fp = 0, temp2_fp = 0; + + s64 LCLK_FAST_SKEW_fp = drm_fixp_from_fraction(6, 10000); /* 0.0006 */ + s64 const_p49_fp = drm_fixp_from_fraction(49, 100); /* 0.49 */ + s64 const_p56_fp = drm_fixp_from_fraction(56, 100); /* 0.56 */ + s64 RATIO_SCALE_fp = drm_fixp_from_fraction(1001, 1000); + + u8 DP_BRUTE_FORCE = 1; + s64 BRUTE_FORCE_THRESHOLD_fp = drm_fixp_from_fraction(1, 10); /* 0.1 */ + uint EXTRA_PIXCLK_CYCLE_DELAY = 4; + uint HBLANK_MARGIN = 4; + + memset(&tu, 0, sizeof(tu)); + + tu.lclk_fp = drm_fixp_from_fraction(in->lclk, 1); + tu.pclk_fp = drm_fixp_from_fraction(in->pclk_khz, 1000); + tu.lwidth = in->hactive; + tu.hbp_relative_to_pclk = in->hporch; + tu.nlanes = in->nlanes; + tu.bpp = in->bpp; + tu.pixelEnc = in->pixel_enc; + tu.dsc_en = in->dsc_en; + tu.async_en = in->async_en; + + tu.err_fp = drm_fixp_from_fraction(1000, 1); /* 1000 */ + + if (tu.pixelEnc == 420) { + temp_fp = drm_fixp_from_fraction(2, 1); + tu.pclk_fp = drm_fixp_div(tu.pclk_fp, temp_fp); + tu.lwidth /= 2; + tu.hbp_relative_to_pclk /= 2; + } - if (n_err < err) { - err = n_err; - tu_size_desired = tu_size; + if (tu.pixelEnc == 422) { + switch (tu.bpp) { + case 24: + tu.bpp = 16; + tu.bpc = 8; + break; + case 30: + tu.bpp = 20; + tu.bpc = 10; + break; + default: + tu.bpp = 16; + tu.bpc = 8; + break; } + } else { + tu.bpc = tu.bpp/3; } - pr_debug("Info: tu_size_desired = %d\n", tu_size_desired); - - tu_size_minus1 = tu_size_desired - 1; - - valid_boundary_link = roundup_u64(ratio * tu_size_desired, multiplier); - valid_boundary_link /= multiplier; - n_tus = rounddown((lwidth * bpp * multiplier) - / (8 * valid_boundary_link), multiplier) / multiplier; - even_distribution_legacy = n_tus % ln_cnt == 0 ? 1 : 0; - pr_debug("Info: n_symbol_per_tu=%d, number_of_tus=%d\n", - valid_boundary_link, n_tus); - - extra_bytes = roundup_u64((n_tus + 1) - * ((valid_boundary_link * multiplier) - - (original_ratio * tu_size_desired)), multiplier); - extra_bytes /= multiplier; - extra_pclk_cycles = roundup(extra_bytes * 8 * multiplier / bpp, - multiplier); - extra_pclk_cycles /= multiplier; - extra_pclk_cycles_in_link_clk = roundup_u64(div64_u64(extra_pclk_cycles - * lclk * multiplier, pclk), multiplier); - extra_pclk_cycles_in_link_clk /= multiplier; - filler_size = roundup_u64((tu_size_desired - valid_boundary_link) - * multiplier, multiplier); - filler_size /= multiplier; - ratio_by_tu = div64_u64(ratio * tu_size_desired, multiplier); - - pr_debug("extra_pclk_cycles_in_link_clk=%d, extra_bytes=%d\n", - extra_pclk_cycles_in_link_clk, extra_bytes); - pr_debug("extra_pclk_cycles_in_link_clk=%d\n", - extra_pclk_cycles_in_link_clk); - pr_debug("filler_size=%d, extra_buffer_margin=%lld\n", - filler_size, extra_buffer_margin); - - delay_start_link = ((extra_bytes > extra_pclk_cycles_in_link_clk) - ? extra_bytes - : extra_pclk_cycles_in_link_clk) - + filler_size + extra_buffer_margin; - resulting_valid = valid_boundary_link; - pr_debug("Info: delay_start_link=%d, filler_size=%d\n", - delay_start_link, filler_size); - pr_debug("valid_boundary_link=%d ratio_by_tu=%lld\n", - valid_boundary_link, ratio_by_tu); - - diff_abs = (resulting_valid >= ratio_by_tu) - ? (resulting_valid - ratio_by_tu) - : (ratio_by_tu - resulting_valid); - - if (err != 0 && ((diff_abs > brute_force_threshold) - || (even_distribution_legacy == 0) - || (dp_brute_force == 1))) { - err = multiplier; - for (tu_size = 32; tu_size <= 64; tu_size++) { - for (i_upper_bdry_cnt = 1; i_upper_bdry_cnt <= 15; - i_upper_bdry_cnt++) { - for (i_lower_bdry_cnt = 1; - i_lower_bdry_cnt <= 15; - i_lower_bdry_cnt++) { - new_valid_boundary_link = - roundup_u64(ratio - * tu_size, multiplier); - average_valid2 = (i_upper_bdry_cnt - * new_valid_boundary_link - + i_lower_bdry_cnt - * (new_valid_boundary_link - - multiplier)) - / (i_upper_bdry_cnt - + i_lower_bdry_cnt); - n_tus = rounddown_u64(div64_u64(lwidth - * multiplier * multiplier - * (bpp / 8), average_valid2), - multiplier); - n_tus /= multiplier; - n_tus_per_lane - = rounddown(n_tus - * multiplier - / ln_cnt, multiplier); - n_tus_per_lane /= multiplier; - paired_tus = - rounddown((n_tus_per_lane) - * multiplier - / (i_upper_bdry_cnt - + i_lower_bdry_cnt), - multiplier); - paired_tus /= multiplier; - remainder_tus = n_tus_per_lane - - paired_tus - * (i_upper_bdry_cnt - + i_lower_bdry_cnt); - if ((remainder_tus - - i_upper_bdry_cnt) > 0) { - remainder_tus_upper - = i_upper_bdry_cnt; - remainder_tus_lower = - remainder_tus - - i_upper_bdry_cnt; - } else { - remainder_tus_upper - = remainder_tus; - remainder_tus_lower = 0; - } - total_valid = paired_tus - * (i_upper_bdry_cnt - * new_valid_boundary_link - + i_lower_bdry_cnt - * (new_valid_boundary_link - - multiplier)) - + (remainder_tus_upper - * new_valid_boundary_link) - + (remainder_tus_lower - * (new_valid_boundary_link - - multiplier)); - n_err_neg = nn_err_neg = false; - effective_valid - = div_u64(total_valid, - n_tus_per_lane); - n_n_err = (effective_valid - >= (ratio * tu_size)) - ? (effective_valid - - (ratio * tu_size)) - : ((ratio * tu_size) - - effective_valid); - if (effective_valid < (ratio * tu_size)) - nn_err_neg = true; - n_err = (average_valid2 - >= (ratio * tu_size)) - ? (average_valid2 - - (ratio * tu_size)) - : ((ratio * tu_size) - - average_valid2); - if (average_valid2 < (ratio * tu_size)) - n_err_neg = true; - even_distribution = - n_tus % ln_cnt == 0 ? 1 : 0; - diff_abs = - resulting_valid >= ratio_by_tu - ? (resulting_valid - - ratio_by_tu) - : (ratio_by_tu - - resulting_valid); - - resulting_valid_tmp = div64_u64( - (i_upper_bdry_cnt - * new_valid_boundary_link - + i_lower_bdry_cnt - * (new_valid_boundary_link - - multiplier)), - (i_upper_bdry_cnt - + i_lower_bdry_cnt)); - ratio_by_tu_tmp = - original_ratio * tu_size; - ratio_by_tu_tmp /= multiplier; - n_tus_tmp = rounddown_u64( - div64_u64(lwidth - * multiplier * multiplier - * bpp / 8, - resulting_valid_tmp), - multiplier); - n_tus_tmp /= multiplier; - - temp3 = (resulting_valid_tmp - >= (original_ratio * tu_size)) - ? (resulting_valid_tmp - - original_ratio * tu_size) - : (original_ratio * tu_size) - - resulting_valid_tmp; - temp3 = (n_tus_tmp + 1) * temp3; - temp4 = (new_valid_boundary_link - >= (original_ratio * tu_size)) - ? (new_valid_boundary_link - - original_ratio - * tu_size) - : (original_ratio * tu_size) - - new_valid_boundary_link; - temp4 = (i_upper_bdry_cnt - * ln_cnt * temp4); - - temp3 = roundup_u64(temp3, multiplier); - temp4 = roundup_u64(temp4, multiplier); - dp_panel_get_extra_req_bytes - (resulting_valid_tmp, - new_valid_boundary_link, - temp3, temp4, - &extra_req_bytes_is_neg, - &result, - (original_ratio * tu_size)); - extra_req_bytes_new_tmp - = div64_ul(result, multiplier); - if ((extra_req_bytes_is_neg) - && (extra_req_bytes_new_tmp - > 1)) - extra_req_bytes_new_tmp - = extra_req_bytes_new_tmp - 1; - if (extra_req_bytes_new_tmp == 0) - extra_req_bytes_new_tmp = 1; - extra_pclk_cycles_tmp = - (int)(extra_req_bytes_new_tmp - * 8 * multiplier) / bpp; - extra_pclk_cycles_tmp /= multiplier; - - if (extra_pclk_cycles_tmp <= 0) - extra_pclk_cycles_tmp = 1; - extra_pclk_cycles_in_lclk_tmp = - roundup_u64(div64_u64( - extra_pclk_cycles_tmp - * lclk * multiplier, - pclk), multiplier); - extra_pclk_cycles_in_lclk_tmp - /= multiplier; - filler_size_tmp = roundup_u64( - (tu_size * multiplier * - new_valid_boundary_link), - multiplier); - filler_size_tmp /= multiplier; - lower_filler_size_tmp = - filler_size_tmp + 1; - if (extra_req_bytes_is_neg) - temp3 = (extra_req_bytes_new_tmp - > extra_pclk_cycles_in_lclk_tmp - ? extra_pclk_cycles_in_lclk_tmp - : extra_req_bytes_new_tmp); - else - temp3 = (extra_req_bytes_new_tmp - > extra_pclk_cycles_in_lclk_tmp - ? extra_req_bytes_new_tmp : - extra_pclk_cycles_in_lclk_tmp); - - temp4 = lower_filler_size_tmp - + extra_buffer_margin; - if (extra_req_bytes_is_neg) - delay_start_link_tmp - = (temp3 >= temp4) - ? (temp3 - temp4) - : (temp4 - temp3); - else - delay_start_link_tmp - = temp3 + temp4; - - min_hblank_tmp = (int)div64_u64( - roundup_u64( - div64_u64(delay_start_link_tmp - * pclk * multiplier, lclk), - multiplier), multiplier) - + hblank_margin; - - if (((even_distribution == 1) - || ((even_distribution_bf == 0) - && (even_distribution_legacy - == 0))) - && !n_err_neg && !nn_err_neg - && n_n_err < err - && (n_n_err < diff_abs - || (dp_brute_force == 1)) - && (new_valid_boundary_link - - 1) > 0 - && (h_blank >= - (u32)min_hblank_tmp)) { - upper_bdry_cnt = - i_upper_bdry_cnt; - lower_bdry_cnt = - i_lower_bdry_cnt; - err = n_n_err; - boundary_moderation_en = 1; - tu_size_desired = tu_size; - valid_boundary_link = - new_valid_boundary_link; - effective_valid_recorded - = effective_valid; - delay_start_link - = delay_start_link_tmp; - filler_size = filler_size_tmp; - min_hblank = min_hblank_tmp; - n_tus = n_tus_tmp; - even_distribution_bf = 1; - - pr_debug("upper_bdry_cnt=%d, lower_boundary_cnt=%d, err=%lld, tu_size_desired=%d, valid_boundary_link=%d, effective_valid=%lld\n", - upper_bdry_cnt, - lower_bdry_cnt, err, - tu_size_desired, - valid_boundary_link, - effective_valid); + + temp1_fp = drm_fixp_from_fraction(4, 1); + temp2_fp = drm_fixp_mul(temp1_fp, tu.lclk_fp); + temp_fp = drm_fixp_div(temp2_fp, tu.pclk_fp); + tu.extra_buffer_margin = drm_fixp2int_ceil(temp_fp); + + temp1_fp = drm_fixp_from_fraction(tu.bpp, 8); + temp2_fp = drm_fixp_mul(tu.pclk_fp, temp1_fp); + temp1_fp = drm_fixp_from_fraction(tu.nlanes, 1); + temp2_fp = drm_fixp_div(temp2_fp, temp1_fp); + tu.ratio_fp = drm_fixp_div(temp2_fp, tu.lclk_fp); + + tu.original_ratio_fp = tu.ratio_fp; + tu.boundary_moderation_en = false; + tu.upper_boundary_count = 0; + tu.lower_boundary_count = 0; + tu.i_upper_boundary_count = 0; + tu.i_lower_boundary_count = 0; + tu.valid_lower_boundary_link = 0; + tu.even_distribution_BF = 0; + tu.even_distribution_legacy = 0; + tu.even_distribution = 0; + tu.delay_start_time_fp = 0; + + tu.err_fp = drm_fixp_from_fraction(1000, 1); + tu.n_err_fp = 0; + tu.n_n_err_fp = 0; + + tu.ratio = drm_fixp2int(tu.ratio_fp); + if ((((u32)tu.lwidth % tu.nlanes) != 0) && + !tu.ratio && tu.dsc_en == 0) { + tu.ratio_fp = drm_fixp_mul(tu.ratio_fp, RATIO_SCALE_fp); + tu.ratio = drm_fixp2int(tu.ratio_fp); + if (tu.ratio) + tu.ratio_fp = drm_fixp_from_fraction(1, 1); + } + + if (tu.ratio > 1) + tu.ratio = 1; + + if (tu.ratio == 1) + goto tu_size_calc; + + compare_result_1 = _tu_param_compare(tu.ratio_fp, const_p49_fp); + if (!compare_result_1 || compare_result_1 == 1) + compare_result_1 = 1; + else + compare_result_1 = 0; + + compare_result_2 = _tu_param_compare(tu.ratio_fp, const_p56_fp); + if (!compare_result_2 || compare_result_2 == 2) + compare_result_2 = 1; + else + compare_result_2 = 0; + + if (tu.dsc_en && compare_result_1 && compare_result_2) { + HBLANK_MARGIN += 4; + pr_info("Info: increase HBLANK_MARGIN to %d\n", HBLANK_MARGIN); + } + +tu_size_calc: + for (tu.tu_size = 32; tu.tu_size <= 64; tu.tu_size++) { + temp1_fp = drm_fixp_from_fraction(tu.tu_size, 1); + temp2_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp); + temp = drm_fixp2int_ceil(temp2_fp); + temp1_fp = drm_fixp_from_fraction(temp, 1); + tu.n_err_fp = temp1_fp - temp2_fp; + + if (tu.n_err_fp < tu.err_fp) { + tu.err_fp = tu.n_err_fp; + tu.tu_size_desired = tu.tu_size; + } + } + + tu.tu_size_minus1 = tu.tu_size_desired - 1; + + temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1); + temp2_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp); + tu.valid_boundary_link = drm_fixp2int_ceil(temp2_fp); + + temp1_fp = drm_fixp_from_fraction(tu.bpp, 8); + temp2_fp = drm_fixp_from_fraction(tu.lwidth, 1); + temp2_fp = drm_fixp_mul(temp2_fp, temp1_fp); + + temp1_fp = drm_fixp_from_fraction(tu.valid_boundary_link, 1); + temp2_fp = drm_fixp_div(temp2_fp, temp1_fp); + tu.n_tus = drm_fixp2int(temp2_fp); + + tu.even_distribution_legacy = tu.n_tus % tu.nlanes == 0 ? 1 : 0; + pr_info("Info: n_sym = %d, num_of_tus = %d\n", + tu.valid_boundary_link, tu.n_tus); + + temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1); + temp2_fp = drm_fixp_mul(tu.original_ratio_fp, temp1_fp); + temp1_fp = drm_fixp_from_fraction(tu.valid_boundary_link, 1); + temp2_fp = temp1_fp - temp2_fp; + temp1_fp = drm_fixp_from_fraction(tu.n_tus + 1, 1); + temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp); + + temp = drm_fixp2int(temp2_fp); + if (temp && temp2_fp) + tu.extra_bytes = drm_fixp2int_ceil(temp2_fp); + else + tu.extra_bytes = 0; + + temp1_fp = drm_fixp_from_fraction(tu.extra_bytes, 1); + temp2_fp = drm_fixp_from_fraction(8, tu.bpp); + temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp); + + temp - drm_fixp2int(temp1_fp); + if (temp && temp1_fp) + tu.extra_pclk_cycles = drm_fixp2int_ceil(temp1_fp); + else + tu.extra_pclk_cycles = 0; + + temp1_fp = drm_fixp_div(tu.lclk_fp, tu.pclk_fp); + temp2_fp = drm_fixp_from_fraction(tu.extra_pclk_cycles, 1); + temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp); + + temp = drm_fixp2int(temp1_fp); + if (temp && temp1_fp) + tu.extra_pclk_cycles_in_link_clk = drm_fixp2int_ceil(temp1_fp); + else + tu.extra_pclk_cycles_in_link_clk = 0; + + tu.filler_size = tu.tu_size_desired - tu.valid_boundary_link; + + temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1); + tu.ratio_by_tu_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp); + + tu.delay_start_link = tu.extra_pclk_cycles_in_link_clk + + tu.filler_size + tu.extra_buffer_margin; + + tu.resulting_valid_fp = + drm_fixp_from_fraction(tu.valid_boundary_link, 1); + + temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1); + temp2_fp = drm_fixp_div(tu.resulting_valid_fp, temp1_fp); + tu.TU_ratio_err_fp = temp2_fp - tu.original_ratio_fp; + + temp1_fp = drm_fixp_from_fraction( + (tu.hbp_relative_to_pclk - HBLANK_MARGIN), 1); + tu.hbp_time_fp = drm_fixp_div(temp1_fp, tu.pclk_fp); + + temp1_fp = drm_fixp_from_fraction(tu.delay_start_link, 1); + tu.delay_start_time_fp = drm_fixp_div(temp1_fp, tu.lclk_fp); + + compare_result_1 = _tu_param_compare(tu.hbp_time_fp, + tu.delay_start_time_fp); + if (compare_result_1 == 2) /* if (hbp_time_fp < delay_start_time_fp) */ + tu.min_hblank_violated = 1; + + temp1_fp = drm_fixp_from_fraction(tu.lwidth, 1); + tu.hactive_time_fp = drm_fixp_div(temp1_fp, tu.pclk_fp); + + compare_result_2 = _tu_param_compare(tu.hactive_time_fp, + tu.delay_start_time_fp); + if (compare_result_2 == 2) + tu.min_hblank_violated = 1; + + tu.delay_start_time_fp = 0; + + /* brute force */ + + tu.delay_start_link_extra_pixclk = EXTRA_PIXCLK_CYCLE_DELAY; + tu.diff_abs_fp = tu.resulting_valid_fp - tu.ratio_by_tu_fp; + + temp = drm_fixp2int(tu.diff_abs_fp); + if (!temp && tu.diff_abs_fp <= 0xffff) + tu.diff_abs_fp = 0; + + /* if(diff_abs < 0) diff_abs *= -1 */ + if (tu.diff_abs_fp < 0) + tu.diff_abs_fp = drm_fixp_mul(tu.diff_abs_fp, -1); + + tu.boundary_mod_lower_err = 0; + if ((tu.diff_abs_fp != 0 && + ((tu.diff_abs_fp > BRUTE_FORCE_THRESHOLD_fp) || + (tu.even_distribution_legacy == 0) || + (DP_BRUTE_FORCE == 1))) || + (tu.min_hblank_violated == 1)) { + do { + tu.err_fp = drm_fixp_from_fraction(1000, 1); + + temp1_fp = drm_fixp_div(tu.lclk_fp, tu.pclk_fp); + temp2_fp = drm_fixp_from_fraction( + tu.delay_start_link_extra_pixclk, 1); + temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp); + + if (temp1_fp) + tu.extra_buffer_margin = + drm_fixp2int_ceil(temp1_fp); + else + tu.extra_buffer_margin = 0; + + temp1_fp = drm_fixp_from_fraction(tu.bpp, 8); + temp2_fp = drm_fixp_from_fraction(tu.lwidth, 1); + temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp); + + if (temp1_fp) + tu.n_symbols = drm_fixp2int_ceil(temp1_fp); + else + tu.n_symbols = 0; + + for (tu.tu_size = 32; tu.tu_size <= 64; tu.tu_size++) { + for (tu.i_upper_boundary_count = 1; + tu.i_upper_boundary_count <= 15; + tu.i_upper_boundary_count++) { + for (tu.i_lower_boundary_count = 1; + tu.i_lower_boundary_count <= 15; + tu.i_lower_boundary_count++) { + _tu_valid_boundary_calc(&tu); } } } - } - - if (boundary_moderation_en == 1) { - resulting_valid = (u32)(upper_bdry_cnt - *valid_boundary_link + lower_bdry_cnt - * (valid_boundary_link - 1)) - / (upper_bdry_cnt + lower_bdry_cnt); - ratio_by_tu = original_ratio * tu_size_desired; - valid_lower_boundary_link = - (valid_boundary_link / multiplier) - 1; - - tu_size_minus1 = tu_size_desired - 1; - even_distribution_bf = 1; - valid_boundary_link /= multiplier; - pr_debug("Info: Boundary_moderation enabled\n"); + tu.delay_start_link_extra_pixclk--; + } while (tu.boundary_moderation_en != true && + tu.boundary_mod_lower_err == 1 && + tu.delay_start_link_extra_pixclk != 0); + + if (tu.boundary_moderation_en == true) { + temp1_fp = drm_fixp_from_fraction( + (tu.upper_boundary_count * + tu.valid_boundary_link + + tu.lower_boundary_count * + (tu.valid_boundary_link - 1)), 1); + temp2_fp = drm_fixp_from_fraction( + (tu.upper_boundary_count + + tu.lower_boundary_count), 1); + tu.resulting_valid_fp = + drm_fixp_div(temp1_fp, temp2_fp); + + temp1_fp = drm_fixp_from_fraction( + tu.tu_size_desired, 1); + tu.ratio_by_tu_fp = + drm_fixp_mul(tu.original_ratio_fp, temp1_fp); + + tu.valid_lower_boundary_link = + tu.valid_boundary_link - 1; + + temp1_fp = drm_fixp_from_fraction(tu.bpp, 8); + temp2_fp = drm_fixp_from_fraction(tu.lwidth, 1); + temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp); + temp2_fp = drm_fixp_div(temp1_fp, + tu.resulting_valid_fp); + tu.n_tus = drm_fixp2int(temp2_fp); + + tu.tu_size_minus1 = tu.tu_size_desired - 1; + tu.even_distribution_BF = 1; + + temp1_fp = + drm_fixp_from_fraction(tu.tu_size_desired, 1); + temp2_fp = + drm_fixp_div(tu.resulting_valid_fp, temp1_fp); + tu.TU_ratio_err_fp = temp2_fp - tu.original_ratio_fp; } } - min_hblank = ((int) roundup_u64(div64_u64(delay_start_link * pclk - * multiplier, lclk), multiplier)) - / multiplier + hblank_margin; - if (h_blank < (u32)min_hblank) { - pr_debug(" WARNING: run_idx=%d Programmed h_blank %d is smaller than the min_hblank %d supported.\n", - run_idx, h_blank, min_hblank); - } + temp1_fp = drm_fixp_from_fraction(tu.lwidth, 1); + temp2_fp = drm_fixp_mul(LCLK_FAST_SKEW_fp, temp1_fp); - if (fifo_empty) { - tu_size_minus1 = 31; - valid_boundary_link = 32; - delay_start_link = 0; - boundary_moderation_en = 0; - } + if (temp2_fp) + temp = drm_fixp2int_ceil(temp2_fp); + else + temp = 0; + + temp1_fp = drm_fixp_from_fraction(tu.nlanes, 1); + temp2_fp = drm_fixp_mul(tu.original_ratio_fp, temp1_fp); + temp1_fp = drm_fixp_from_fraction(tu.bpp, 8); + temp2_fp = drm_fixp_div(temp1_fp, temp2_fp); + temp1_fp = drm_fixp_from_fraction(temp, 1); + temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp); + temp = drm_fixp2int(temp2_fp); + + if (tu.async_en) + tu.delay_start_link += (int)temp; + + temp1_fp = drm_fixp_from_fraction(tu.delay_start_link, 1); + tu.delay_start_time_fp = drm_fixp_div(temp1_fp, tu.lclk_fp); + + /* OUTPUTS */ + tu_table->valid_boundary_link = tu.valid_boundary_link; + tu_table->delay_start_link = tu.delay_start_link; + tu_table->boundary_moderation_en = tu.boundary_moderation_en; + tu_table->valid_lower_boundary_link = tu.valid_lower_boundary_link; + tu_table->upper_boundary_count = tu.upper_boundary_count; + tu_table->lower_boundary_count = tu.lower_boundary_count; + tu_table->tu_size_minus1 = tu.tu_size_minus1; + + pr_info("TU: valid_boundary_link: %d\n", tu_table->valid_boundary_link); + pr_info("TU: delay_start_link: %d\n", tu_table->delay_start_link); + pr_info("TU: boundary_moderation_en: %d\n", + tu_table->boundary_moderation_en); + pr_info("TU: valid_lower_boundary_link: %d\n", + tu_table->valid_lower_boundary_link); + pr_info("TU: upper_boundary_count: %d\n", + tu_table->upper_boundary_count); + pr_info("TU: lower_boundary_count: %d\n", + tu_table->lower_boundary_count); + pr_info("TU: tu_size_minus1: %d\n", tu_table->tu_size_minus1); +} + +static void dp_panel_calc_tu_parameters(struct dp_panel *dp_panel, + struct dp_vc_tu_mapping_table *tu_table) +{ + struct dp_tu_calc_input in; + struct dp_panel_info *pinfo; + struct dp_panel_private *panel; + int bw_code; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + pinfo = &dp_panel->pinfo; + bw_code = panel->link->link_params.bw_code; + + in.lclk = drm_dp_bw_code_to_link_rate(bw_code) / 1000; + in.pclk_khz = pinfo->pixel_clk_khz; + in.hactive = pinfo->h_active; + in.hporch = pinfo->h_back_porch + pinfo->h_front_porch + + pinfo->h_sync_width; + in.nlanes = panel->link->link_params.lane_count; + in.bpp = pinfo->bpp; + in.pixel_enc = 444; + in.dsc_en = 0; + in.async_en = 0; + + _dp_panel_calc_tu(&in, tu_table); +} - pr_debug("tu_size_minus1=%d valid_boundary_link=%d delay_start_link=%d boundary_moderation_en=%d\n upper_boundary_cnt=%d lower_boundary_cnt=%d valid_lower_boundary_link=%d min_hblank=%d\n", - tu_size_minus1, valid_boundary_link, delay_start_link, - boundary_moderation_en, upper_bdry_cnt, lower_bdry_cnt, - valid_lower_boundary_link, min_hblank); - - tu_table->valid_boundary_link = valid_boundary_link; - tu_table->delay_start_link = delay_start_link; - tu_table->boundary_moderation_en = boundary_moderation_en; - tu_table->valid_lower_boundary_link = valid_lower_boundary_link; - tu_table->upper_boundary_count = upper_bdry_cnt; - tu_table->lower_boundary_count = lower_bdry_cnt; - tu_table->tu_size_minus1 = tu_size_minus1; +void dp_panel_calc_tu_test(struct dp_tu_calc_input *in, + struct dp_vc_tu_mapping_table *tu_table) +{ + _dp_panel_calc_tu(in, tu_table); } static void dp_panel_config_tr_unit(struct dp_panel *dp_panel) @@ -835,11 +1019,11 @@ static int dp_panel_read_edid(struct dp_panel *dp_panel, { int ret = 0; struct dp_panel_private *panel; + struct edid *edid; if (!dp_panel) { pr_err("invalid input\n"); - ret = -EINVAL; - goto end; + return -EINVAL; } panel = container_of(dp_panel, struct dp_panel_private, dp_panel); @@ -857,6 +1041,9 @@ static int dp_panel_read_edid(struct dp_panel *dp_panel, goto end; } end: + edid = dp_panel->edid_ctrl->edid; + dp_panel->audio_supported = drm_detect_monitor_audio(edid); + return ret; } @@ -911,6 +1098,8 @@ static int dp_panel_read_sink_caps(struct dp_panel *dp_panel, pr_err("panel edid read failed, set failsafe mode\n"); return rc; } + + dp_panel->widebus_en = panel->parser->has_widebus; end: return rc; } @@ -1163,6 +1352,8 @@ static int dp_panel_config_timing(struct dp_panel *dp_panel) catalog->dp_active = data; + catalog->widebus_en = pinfo->widebus_en; + panel->catalog->timing_cfg(catalog); panel->panel_on = true; end: @@ -1511,6 +1702,8 @@ static void dp_panel_config_msa(struct dp_panel *dp_panel) panel = container_of(dp_panel, struct dp_panel_private, dp_panel); catalog = panel->catalog; + catalog->widebus_en = dp_panel->widebus_en; + fixed_nvid = dp_panel_use_fixed_nvid(dp_panel); rate = drm_dp_bw_code_to_link_rate(panel->link->link_params.bw_code); stream_rate_khz = dp_panel->pinfo.pixel_clk_khz; @@ -1647,6 +1840,8 @@ static void dp_panel_convert_to_dp_mode(struct dp_panel *dp_panel, dp_mode->timing.bpp = dp_panel_get_mode_bpp(dp_panel, dp_mode->timing.bpp, dp_mode->timing.pixel_clk_khz); + + dp_mode->timing.widebus_en = dp_panel->widebus_en; } struct dp_panel *dp_panel_get(struct dp_panel_in *in) @@ -1673,6 +1868,7 @@ struct dp_panel *dp_panel_get(struct dp_panel_in *in) panel->aux = in->aux; panel->catalog = in->catalog; panel->link = in->link; + panel->parser = in->parser; dp_panel = &panel->dp_panel; dp_panel->max_bw_code = DP_LINK_BW_8_1; @@ -1681,6 +1877,8 @@ struct dp_panel *dp_panel_get(struct dp_panel_in *in) memcpy(panel->spd_product_description, product_desc, (sizeof(u8) * 16)); dp_panel->connector = in->connector; + dp_panel->widebus_en = panel->parser->has_widebus; + if (in->base_panel) { memcpy(dp_panel->dpcd, in->base_panel->dpcd, DP_RECEIVER_CAP_SIZE + 1); diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h index 41488858b77775d339e7a15741971c6026ca6a53..4d2e48ad8f44b0bd31f12d16274796a3d11999d1 100644 --- a/drivers/gpu/drm/msm/dp/dp_panel.h +++ b/drivers/gpu/drm/msm/dp/dp_panel.h @@ -46,6 +46,7 @@ struct dp_panel_info { u32 refresh_rate; u32 pixel_clk_khz; u32 bpp; + bool widebus_en; }; struct dp_display_mode { @@ -62,6 +63,7 @@ struct dp_panel_in { struct dp_catalog_panel *catalog; struct drm_connector *connector; struct dp_panel *base_panel; + struct dp_parser *parser; }; struct dp_audio; @@ -97,6 +99,7 @@ struct dp_panel { struct dp_audio *audio; bool audio_supported; + bool widebus_en; int (*init)(struct dp_panel *dp_panel); int (*deinit)(struct dp_panel *dp_panel); @@ -129,6 +132,32 @@ struct dp_panel { struct dp_display_mode *dp_mode); }; +struct dp_tu_calc_input { + u64 lclk; /* 162, 270, 540 and 810 */ + u64 pclk_khz; /* in KHz */ + u64 hactive; /* active h-width */ + u64 hporch; /* bp + fp + pulse */ + int nlanes; /* no.of.lanes */ + int bpp; /* bits */ + int pixel_enc; /* 444, 420, 422 */ + int dsc_en; /* dsc on/off */ + int async_en; /* async mode */ +}; + +struct dp_vc_tu_mapping_table { + u32 vic; + u8 lanes; + u8 lrate; /* DP_LINK_RATE -> 162(6), 270(10), 540(20), 810 (30) */ + u8 bpp; + u32 valid_boundary_link; + u32 delay_start_link; + bool boundary_moderation_en; + u32 valid_lower_boundary_link; + u32 upper_boundary_count; + u32 lower_boundary_count; + u32 tu_size_minus1; +}; + /** * is_link_rate_valid() - validates the link rate * @lane_rate: link rate requested by the sink @@ -158,4 +187,6 @@ static inline bool is_lane_count_valid(u32 lane_count) struct dp_panel *dp_panel_get(struct dp_panel_in *in); void dp_panel_put(struct dp_panel *dp_panel); +void dp_panel_calc_tu_test(struct dp_tu_calc_input *in, + struct dp_vc_tu_mapping_table *tu_table); #endif /* _DP_PANEL_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c b/drivers/gpu/drm/msm/dp/dp_parser.c index 3d688d594d1540687f1a64d9a719aeca5ebce513..a315b736b37911315919defc48b63345f899d668 100644 --- a/drivers/gpu/drm/msm/dp/dp_parser.c +++ b/drivers/gpu/drm/msm/dp/dp_parser.c @@ -687,6 +687,18 @@ static int dp_parser_mst(struct dp_parser *parser) return 0; } +static int dp_parser_widebus(struct dp_parser *parser) +{ + struct device *dev = &parser->pdev->dev; + + parser->has_widebus = of_property_read_bool(dev->of_node, + "qcom,widebus-enable"); + + pr_debug("widebus parsing successful. dsc:%d\n", parser->has_widebus); + + return 0; +} + static int dp_parser_parse(struct dp_parser *parser) { int rc = 0; @@ -734,6 +746,10 @@ static int dp_parser_parse(struct dp_parser *parser) goto err; rc = dp_parser_mst(parser); + if (rc) + goto err; + + rc = dp_parser_widebus(parser); err: return rc; } diff --git a/drivers/gpu/drm/msm/dp/dp_parser.h b/drivers/gpu/drm/msm/dp/dp_parser.h index 3c459718d09d87dd6da5aa14525767e4df4e7192..584ba60e45a32299a16d348bff0a2bb57396db15 100644 --- a/drivers/gpu/drm/msm/dp/dp_parser.h +++ b/drivers/gpu/drm/msm/dp/dp_parser.h @@ -209,6 +209,7 @@ struct dp_parser { bool has_mst; bool has_mst_sideband; bool no_aux_switch; + bool has_widebus; int (*parse)(struct dp_parser *parser); struct dp_io_data *(*get_io)(struct dp_parser *parser, char *name); diff --git a/drivers/gpu/drm/msm/dp/dp_power.c b/drivers/gpu/drm/msm/dp/dp_power.c index b326fce482b0efeb063fe18488234f83c3eac066..7a3c7ecad8869449680b6f09a63d9fbb48e02065 100644 --- a/drivers/gpu/drm/msm/dp/dp_power.c +++ b/drivers/gpu/drm/msm/dp/dp_power.c @@ -123,6 +123,9 @@ static int dp_power_pinctrl_set(struct dp_power_private *power, bool active) parser = power->parser; + if (parser && parser->no_aux_switch) + return 0; + if (IS_ERR_OR_NULL(parser->pinctrl.pin)) return PTR_ERR(parser->pinctrl.pin); diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c index 85d1f0c8eff3e0cf63c5fb046ffe55c83d884758..b0e0f42a3244c466eca4c8debf64dc30d17e4132 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c @@ -848,12 +848,12 @@ static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl, if (host_cfg->data_lanes & DSI_DATA_LANE_3) num_of_lanes++; - if (config->bit_clk_rate_hz == 0) { + if (config->bit_clk_rate_hz_override == 0) { h_period = DSI_H_TOTAL_DSC(timing); v_period = DSI_V_TOTAL(timing); bit_rate = h_period * v_period * timing->refresh_rate * bpp; } else { - bit_rate = config->bit_clk_rate_hz * num_of_lanes; + bit_rate = config->bit_clk_rate_hz_override * num_of_lanes; } bit_rate_per_lane = bit_rate; @@ -870,6 +870,7 @@ static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl, dsi_ctrl->clk_freq.byte_clk_rate = byte_clk_rate; dsi_ctrl->clk_freq.pix_clk_rate = pclk_rate; dsi_ctrl->clk_freq.esc_clk_rate = config->esc_clk_rate_hz; + config->bit_clk_rate_hz = dsi_ctrl->clk_freq.byte_clk_rate * 8; rc = dsi_clk_set_link_frequencies(clk_handle, dsi_ctrl->clk_freq, dsi_ctrl->cell_index); @@ -1194,6 +1195,11 @@ static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl, } kickoff: + /* check if custom dma scheduling line needed */ + if ((dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) && + (flags & DSI_CTRL_CMD_CUSTOM_DMA_SCHED)) + line_no = dsi_ctrl->host_config.u.video_engine.dma_sched_line; + timing = &(dsi_ctrl->host_config.video_timing); if (timing) line_no += timing->v_back_porch + timing->v_sync_width + diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h index 573ac2967adc13e09b19f8e6e7cc036cfa29fd17..a33b6a5c99e1b1550f078ee4c99b7c972890af40 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h @@ -38,6 +38,8 @@ * @DSI_CTRL_CMD_LAST_COMMAND: Trigger the DMA cmd transfer if this is last * command in the batch. * @DSI_CTRL_CMD_NON_EMBEDDED_MODE:Transfer cmd packets in non embedded mode. + * @DSI_CTRL_CMD_CUSTOM_DMA_SCHED: Use the dma scheduling line number defined in + * display panel dtsi file instead of default. */ #define DSI_CTRL_CMD_READ 0x1 #define DSI_CTRL_CMD_BROADCAST 0x2 @@ -47,6 +49,7 @@ #define DSI_CTRL_CMD_FETCH_MEMORY 0x20 #define DSI_CTRL_CMD_LAST_COMMAND 0x40 #define DSI_CTRL_CMD_NON_EMBEDDED_MODE 0x80 +#define DSI_CTRL_CMD_CUSTOM_DMA_SCHED 0x100 /* DSI embedded mode fifo size * If the command is greater than 256 bytes it is sent in non-embedded mode. diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c index 470cc66f0ff177b88b5b3a5392a0e2f752247bb0..a41411ce691205ff54578d23b6e5755bc8f0a1b9 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c @@ -1379,7 +1379,7 @@ void dsi_ctrl_hw_dln0_phy_err(struct dsi_ctrl_hw *ctrl) status = DSI_R32(ctrl, DSI_DLN0_PHY_ERR); if (status & 0x011111) { DSI_W32(ctrl, DSI_DLN0_PHY_ERR, status); - pr_err("%s: phy_err_status = %x\n", __func__, status); + pr_debug("%s: phy_err_status = %x\n", __func__, status); } } diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h b/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h index 60ae85da501668b5ab1f29d982d4594a92f71102..d1d39c184b325bbd195084deec949ecce455d601 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h @@ -458,6 +458,8 @@ struct dsi_host_common_cfg { * @bllp_lp11_en: Enter low power stop mode (LP-11) during BLLP. * @traffic_mode: Traffic mode for video stream. * @vc_id: Virtual channel identifier. + * @dma_sched_line: Line number, after vactive end, at which command dma + * needs to be triggered. */ struct dsi_video_engine_cfg { bool last_line_interleave_en; @@ -470,6 +472,7 @@ struct dsi_video_engine_cfg { bool force_clk_lane_hs; enum dsi_video_traffic_mode traffic_mode; u32 vc_id; + u32 dma_sched_line; }; /** @@ -500,6 +503,7 @@ struct dsi_cmd_engine_cfg { * @cmd_engine: Cmd engine configuration if panel is in cmd mode. * @esc_clk_rate_khz: Esc clock frequency in Hz. * @bit_clk_rate_hz: Bit clock frequency in Hz. + * @bit_clk_rate_hz_override: DSI bit clk rate override from dt/sysfs. * @video_timing: Video timing information of a frame. * @lane_map: Mapping between logical and physical lanes. */ @@ -512,6 +516,7 @@ struct dsi_host_config { } u; u64 esc_clk_rate_hz; u64 bit_clk_rate_hz; + u64 bit_clk_rate_hz_override; struct dsi_mode_info video_timing; struct dsi_lane_map lane_map; }; diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c index 847553ba412220f2b93c43686e463bbea27276b2..bbeaffc799810053d0c39bbc67373de84f2a5c4e 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c @@ -643,7 +643,8 @@ static int dsi_display_read_status(struct dsi_display_ctrl *ctrl, lenp = config->status_valid_params ?: config->status_cmds_rlen; count = config->status_cmd.count; cmds = config->status_cmd.cmds; - flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ); + flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ | + DSI_CTRL_CMD_CUSTOM_DMA_SCHED); for (i = 0; i < count; ++i) { memset(config->status_buf, 0x0, SZ_4K); @@ -919,6 +920,17 @@ int dsi_display_cmd_transfer(struct drm_connector *connector, mutex_lock(&dsi_display->display_lock); rc = dsi_display_ctrl_get_host_init_state(dsi_display, &state); + + /** + * Handle scenario where a command transfer is initiated through + * sysfs interface when device is in suepnd state. + */ + if (!rc && !state) { + pr_warn_ratelimited("Command xfer attempted while device is in suspend state\n" + ); + rc = -EPERM; + goto end; + } if (rc || !state) { pr_err("[DSI] Invalid host state %d rc %d\n", state, rc); @@ -1316,7 +1328,7 @@ static ssize_t debugfs_alter_esd_check_mode(struct file *file, if (ZERO_OR_NULL_PTR(buf)) return -ENOMEM; - if (copy_from_user(buf, user_buf, user_len)) { + if (copy_from_user(buf, user_buf, len)) { rc = -EINVAL; goto error; } @@ -3010,7 +3022,7 @@ int dsi_pre_clkoff_cb(void *priv, struct dsi_display_ctrl *ctrl; if ((clk & DSI_LINK_CLK) && (new_state == DSI_CLK_OFF) && - (l_type && DSI_LINK_LP_CLK)) { + (l_type & DSI_LINK_LP_CLK)) { /* * If continuous clock is enabled then disable it * before entering into ULPS Mode. @@ -3033,6 +3045,20 @@ int dsi_pre_clkoff_cb(void *priv, __func__, rc); } + if ((clk & DSI_LINK_CLK) && (new_state == DSI_CLK_OFF) && + (l_type & DSI_LINK_HS_CLK)) { + /* + * PHY clock gating should be disabled before the PLL and the + * branch clocks are turned off. Otherwise, it is possible that + * the clock RCGs may not be turned off correctly resulting + * in clock warnings. + */ + rc = dsi_display_config_clk_gating(display, false); + if (rc) + pr_err("[%s] failed to disable clk gating, rc=%d\n", + display->name, rc); + } + if ((clk & DSI_CORE_CLK) && (new_state == DSI_CLK_OFF)) { /* * Enable DSI clamps only if entering idle power collapse or @@ -3045,10 +3071,6 @@ int dsi_pre_clkoff_cb(void *priv, if (rc) pr_err("%s: Failed to enable dsi clamps. rc=%d\n", __func__, rc); - rc = dsi_display_config_clk_gating(display, false); - if (rc) - pr_err("[%s] failed to disable clk gating, rc=%d\n", - display->name, rc); rc = dsi_display_phy_reset_config(display, false); if (rc) @@ -3128,13 +3150,6 @@ int dsi_post_clkon_cb(void *priv, } } - rc = dsi_display_config_clk_gating(display, true); - if (rc) { - pr_err("[%s] failed to enable clk gating %d\n", - display->name, rc); - goto error; - } - rc = dsi_display_phy_reset_config(display, true); if (rc) { pr_err("%s: Failed to reset phy, rc=%d\n", @@ -3171,6 +3186,13 @@ int dsi_post_clkon_cb(void *priv, if (display->panel->host_config.force_hs_clk_lane) _dsi_display_continuous_clk_ctrl(display, true); + + rc = dsi_display_config_clk_gating(display, true); + if (rc) { + pr_err("[%s] failed to enable clk gating %d\n", + display->name, rc); + goto error; + } } /* enable dsi to serve irqs */ @@ -4200,7 +4222,7 @@ static int dsi_display_request_update_dsi_bitrate(struct dsi_display *display, return -EINVAL; } - display->config.bit_clk_rate_hz = bit_clk_rate; + display->config.bit_clk_rate_hz_override = bit_clk_rate; for (i = 0; i < display->ctrl_count; i++) { struct dsi_display_ctrl *dsi_disp_ctrl = &display->ctrl[i]; @@ -4228,7 +4250,8 @@ static int dsi_display_request_update_dsi_bitrate(struct dsi_display *display, goto error; } - bit_rate = display->config.bit_clk_rate_hz * num_of_lanes; + bit_rate = display->config.bit_clk_rate_hz_override * + num_of_lanes; bit_rate_per_lane = bit_rate; do_div(bit_rate_per_lane, num_of_lanes); pclk_rate = bit_rate; @@ -4249,7 +4272,7 @@ static int dsi_display_request_update_dsi_bitrate(struct dsi_display *display, goto error; } - ctrl->host_config.bit_clk_rate_hz = bit_clk_rate; + ctrl->host_config.bit_clk_rate_hz_override = bit_clk_rate; error: mutex_unlock(&ctrl->ctrl_lock); @@ -4786,12 +4809,6 @@ int dsi_display_dev_probe(struct platform_device *pdev) break; } continue; - } else if (index == DSI_SECONDARY) { - /* - * secondary display is currently - * supported through boot params only - */ - break; } if (of_property_read_bool(np, disp_active)) { @@ -6099,6 +6116,9 @@ int dsi_display_prepare(struct dsi_display *display) dsi_display_set_ctrl_esd_check_flag(display, false); + /* Set up ctrl isr before enabling core clk */ + dsi_display_ctrl_isr_configure(display, true); + if (mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) { if (display->is_cont_splash_enabled) { pr_err("DMS is not supposed to be set on first frame\n"); @@ -6126,9 +6146,6 @@ int dsi_display_prepare(struct dsi_display *display) } } - /* Set up ctrl isr before enabling core clk */ - dsi_display_ctrl_isr_configure(display, true); - rc = dsi_display_clk_ctrl(display->dsi_clk_handle, DSI_CORE_CLK, DSI_CLK_ON); if (rc) { diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c index bc485f569cf73400979acb5cd10baa16299c6cba..68e3e000db965dff3cc4b501a69d31a46daaad1d 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c @@ -546,6 +546,9 @@ static int dsi_panel_pinctrl_deinit(struct dsi_panel *panel) { int rc = 0; + if (panel->host_config.ext_bridge_mode) + return 0; + devm_pinctrl_put(panel->pinctrl.pinctrl); return rc; @@ -628,6 +631,9 @@ int dsi_panel_set_backlight(struct dsi_panel *panel, u32 bl_lvl) int rc = 0; struct dsi_backlight_config *bl = &panel->bl_config; + if (panel->host_config.ext_bridge_mode) + return 0; + pr_debug("backlight type:%d lvl:%d\n", bl->type, bl_lvl); switch (bl->type) { case DSI_BACKLIGHT_WLED: @@ -1210,6 +1216,7 @@ static int dsi_panel_parse_video_host_config(struct dsi_video_engine_cfg *cfg, const char *traffic_mode; u32 vc_id = 0; u32 val = 0; + u32 line_no = 0; rc = utils->read_u32(utils->data, "qcom,mdss-dsi-h-sync-pulse", &val); if (rc) { @@ -1275,6 +1282,17 @@ static int dsi_panel_parse_video_host_config(struct dsi_video_engine_cfg *cfg, cfg->vc_id = vc_id; } + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-dma-schedule-line", + &line_no); + if (rc) { + pr_debug("[%s] set default dma scheduling line no\n", name); + cfg->dma_sched_line = 0x1; + /* do not fail since we have default value */ + rc = 0; + } else { + cfg->dma_sched_line = line_no; + } + error: return rc; } @@ -1967,6 +1985,7 @@ static int dsi_panel_parse_bl_config(struct dsi_panel *panel) int rc = 0; u32 val = 0; const char *bl_type; + const char *data; struct dsi_parser_utils *utils = &panel->utils; bl_type = utils->get_property(utils->data, @@ -1986,6 +2005,17 @@ static int dsi_panel_parse_bl_config(struct dsi_panel *panel) panel->bl_config.type = DSI_BACKLIGHT_UNKNOWN; } + data = utils->get_property(utils->data, "qcom,bl-update-flag", NULL); + if (!data) { + panel->bl_config.bl_update = BL_UPDATE_NONE; + } else if (!strcmp(data, "delay_until_first_frame")) { + panel->bl_config.bl_update = BL_UPDATE_DELAY_UNTIL_FIRST_FRAME; + } else { + pr_debug("[%s] No valid bl-update-flag: %s\n", + panel->name, data); + panel->bl_config.bl_update = BL_UPDATE_NONE; + } + panel->bl_config.bl_scale = MAX_BL_SCALE_LEVEL; panel->bl_config.bl_scale_ad = MAX_AD_BL_SCALE_LEVEL; @@ -2339,11 +2369,13 @@ static int dsi_panel_parse_dsc_params(struct dsi_display_mode *mode, priv_info->dsc.pic_width = mode->timing.h_active; priv_info->dsc.pic_height = mode->timing.v_active; - rc = utils->read_u32(utils->data, "qcom,mdss-dsc-slice-per-pkt", - &data); + rc = utils->read_u32(utils->data, "qcom,mdss-dsc-slice-per-pkt", &data); if (rc) { pr_err("failed to parse qcom,mdss-dsc-slice-per-pkt\n"); goto error; + } else if (!data || (data > 2)) { + pr_err("invalid dsc slice-per-pkt:%d\n", data); + goto error; } priv_info->dsc.slice_per_pkt = data; @@ -3330,7 +3362,7 @@ int dsi_panel_get_host_cfg_for_mode(struct dsi_panel *panel, config->video_timing.dsc_enabled = mode->priv_info->dsc_enabled; config->video_timing.dsc = &mode->priv_info->dsc; - config->bit_clk_rate_hz = mode->priv_info->clk_rate_hz; + config->bit_clk_rate_hz_override = mode->priv_info->clk_rate_hz; config->esc_clk_rate_hz = 19200000; mutex_unlock(&panel->panel_lock); return rc; diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h index 13b4393587428fe9dd4d5a923e67cc358f0f8e54..454732d3295f67e662e471c4e829436178ba28d8 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h @@ -52,6 +52,11 @@ enum dsi_backlight_type { DSI_BACKLIGHT_MAX, }; +enum bl_update_flag { + BL_UPDATE_DELAY_UNTIL_FIRST_FRAME, + BL_UPDATE_NONE, +}; + enum { MODE_GPIO_NOT_VALID = 0, MODE_SEL_DUAL_PORT, @@ -86,6 +91,7 @@ struct dsi_panel_phy_props { struct dsi_backlight_config { enum dsi_backlight_type type; + enum bl_update_flag bl_update; u32 bl_min_level; u32 bl_max_level; diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c index b3e375e1940a724aed463b3820bbc03b4e4163ba..65f89f40442d3540d53f02fca3814384a76aca6f 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c @@ -864,6 +864,7 @@ int dsi_phy_enable(struct msm_dsi_phy *phy, phy->data_lanes = config->common_config.data_lanes; phy->dst_format = config->common_config.dst_format; phy->cfg.pll_source = pll_source; + phy->cfg.bit_clk_rate_hz = config->bit_clk_rate_hz; /** * If PHY timing parameters are not present in panel dtsi file, diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h index ae3080a86eb69965935771f9801ed2a2431186e3..74a5c371d5d8cdeafddbeb7ddcf033de11369b65 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h @@ -93,6 +93,7 @@ struct dsi_phy_per_lane_cfgs { * @pll_source: PLL source. * @lane_map: DSI logical to PHY lane mapping. * @force_clk_lane_hs:Boolean whether to force clock lane in HS mode. + * @bit_clk_rate_hz: DSI bit clk rate in HZ. */ struct dsi_phy_cfg { struct dsi_phy_per_lane_cfgs lanecfg; @@ -103,6 +104,7 @@ struct dsi_phy_cfg { enum dsi_phy_pll_source pll_source; struct dsi_lane_map lane_map; bool force_clk_lane_hs; + unsigned long bit_clk_rate_hz; }; struct dsi_phy_hw; diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c index 4fdb028e0388e80e697c51360bd4887b9f8cfd1d..8f375d717bc2c6dd0c1f98ce8c136e4e7357a3f0 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c @@ -333,7 +333,8 @@ int dsi_phy_hw_v3_0_wait_for_lane_idle( pr_debug("%s: polling for lanes to be in stop state, mask=0x%08x\n", __func__, stop_state_mask); rc = readl_poll_timeout(phy->base + DSIPHY_CMN_LANE_STATUS1, val, - (val == stop_state_mask), sleep_us, timeout_us); + ((val & stop_state_mask) == stop_state_mask), + sleep_us, timeout_us); if (rc) { pr_err("%s: lanes not in stop state, LANE_STATUS=0x%08x\n", __func__, val); diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v4_0.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v4_0.c index 9123cf852c33ccd937d4a99fa4fb309c0bd12820..7cd47030c2fff61bf00ba0c4ee7463b1961c5b05 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v4_0.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v4_0.c @@ -166,6 +166,10 @@ void dsi_phy_hw_v4_0_enable(struct dsi_phy_hw *phy, u32 const timeout_us = 1000; struct dsi_phy_per_lane_cfgs *timing = &cfg->timing; u32 data; + bool less_than_1500_mhz = false; + u32 vreg_ctrl_0 = 0; + u32 glbl_str_swi_cal_sel_ctrl = 0; + u32 glbl_hstx_str_ctrl_0 = 0; if (dsi_phy_hw_v4_0_is_pll_on(phy)) pr_warn("PLL turned on before configuring PHY\n"); @@ -178,6 +182,13 @@ void dsi_phy_hw_v4_0_enable(struct dsi_phy_hw *phy, return; } + /* Alter PHY configurations if data rate less than 1.5GHZ*/ + if (cfg->bit_clk_rate_hz < 1500000000) + less_than_1500_mhz = true; + vreg_ctrl_0 = less_than_1500_mhz ? 0x5B : 0x59; + glbl_str_swi_cal_sel_ctrl = less_than_1500_mhz ? 0x03 : 0x00; + glbl_hstx_str_ctrl_0 = less_than_1500_mhz ? 0x66 : 0x88; + /* de-assert digital and pll power down */ data = BIT(6) | BIT(5); DSI_W32(phy, DSIPHY_CMN_CTRL_0, data); @@ -192,11 +203,12 @@ void dsi_phy_hw_v4_0_enable(struct dsi_phy_hw *phy, dsi_phy_hw_v4_0_lane_swap_config(phy, &cfg->lane_map); /* Enable LDO */ - DSI_W32(phy, DSIPHY_CMN_VREG_CTRL_0, 0x59); + DSI_W32(phy, DSIPHY_CMN_VREG_CTRL_0, vreg_ctrl_0); DSI_W32(phy, DSIPHY_CMN_VREG_CTRL_1, 0x19); DSI_W32(phy, DSIPHY_CMN_CTRL_3, 0x00); - DSI_W32(phy, DSIPHY_CMN_GLBL_STR_SWI_CAL_SEL_CTRL, 0x00); - DSI_W32(phy, DSIPHY_CMN_GLBL_HSTX_STR_CTRL_0, 0x88); + DSI_W32(phy, DSIPHY_CMN_GLBL_STR_SWI_CAL_SEL_CTRL, + glbl_str_swi_cal_sel_ctrl); + DSI_W32(phy, DSIPHY_CMN_GLBL_HSTX_STR_CTRL_0, glbl_hstx_str_ctrl_0); DSI_W32(phy, DSIPHY_CMN_GLBL_PEMPH_CTRL_0, 0x00); DSI_W32(phy, DSIPHY_CMN_GLBL_RESCODE_OFFSET_TOP_CTRL, 0x00); DSI_W32(phy, DSIPHY_CMN_GLBL_RESCODE_OFFSET_BOT_CTRL, 0x00); @@ -315,7 +327,8 @@ int dsi_phy_hw_v4_0_wait_for_lane_idle( pr_debug("%s: polling for lanes to be in stop state, mask=0x%08x\n", __func__, stop_state_mask); rc = readl_poll_timeout(phy->base + DSIPHY_CMN_LANE_STATUS1, val, - (val == stop_state_mask), sleep_us, timeout_us); + ((val & stop_state_mask) == stop_state_mask), + sleep_us, timeout_us); if (rc) { pr_err("%s: lanes not in stop state, LANE_STATUS=0x%08x\n", __func__, val); diff --git a/drivers/gpu/drm/msm/sde/sde_color_processing.c b/drivers/gpu/drm/msm/sde/sde_color_processing.c index 265c1c78029f0cc2df264defbf64e69359e2b17e..19300857d8bb59a5f0b31ccad03088a61317b6b6 100644 --- a/drivers/gpu/drm/msm/sde/sde_color_processing.c +++ b/drivers/gpu/drm/msm/sde/sde_color_processing.c @@ -1430,7 +1430,9 @@ static void dspp_ad_install_property(struct drm_crtc *crtc) SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS, 0, (BIT(8) - 1), 0); sde_cp_crtc_install_range_property(crtc, "SDE_DSPP_AD_V4_STRENGTH", - SDE_CP_CRTC_DSPP_AD_STRENGTH, 0, (BIT(10) - 1), 0); + SDE_CP_CRTC_DSPP_AD_STRENGTH, 0, U64_MAX, 0); + sde_cp_create_local_blob(crtc, SDE_CP_CRTC_DSPP_AD_STRENGTH, + sizeof(struct drm_msm_ad4_manual_str_cfg)); sde_cp_crtc_install_range_property(crtc, "SDE_DSPP_AD_V4_INPUT", SDE_CP_CRTC_DSPP_AD_INPUT, 0, U16_MAX, 0); sde_cp_crtc_install_range_property(crtc, diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c index 2652daea0889418d0d6b4f8f5462a44bd2c0810e..dada88aca3e637dd8f9b4d0017201b9a3d789571 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.c +++ b/drivers/gpu/drm/msm/sde/sde_connector.c @@ -94,6 +94,12 @@ static int sde_backlight_device_update_status(struct backlight_device *bd) if (!bl_lvl && brightness) bl_lvl = 1; + if (display->panel->bl_config.bl_update == + BL_UPDATE_DELAY_UNTIL_FIRST_FRAME && !c_conn->allow_bl_update) { + c_conn->unset_bl_level = bl_lvl; + return 0; + } + if (c_conn->ops.set_backlight) { event.type = DRM_EVENT_SYS_BACKLIGHT; event.length = sizeof(u32); @@ -101,6 +107,7 @@ static int sde_backlight_device_update_status(struct backlight_device *bd) c_conn->base.dev, &event, (u8 *)&brightness); rc = c_conn->ops.set_backlight(&c_conn->base, c_conn->display, bl_lvl); + c_conn->unset_bl_level = 0; } return rc; @@ -526,6 +533,15 @@ static int _sde_connector_update_bl_scale(struct sde_connector *c_conn) bl_config = &dsi_display->panel->bl_config; + if (dsi_display->panel->bl_config.bl_update == + BL_UPDATE_DELAY_UNTIL_FIRST_FRAME && !c_conn->allow_bl_update) { + c_conn->unset_bl_level = bl_config->bl_level; + return 0; + } + + if (c_conn->unset_bl_level) + bl_config->bl_level = c_conn->unset_bl_level; + if (c_conn->bl_scale > MAX_BL_SCALE_LEVEL) bl_config->bl_scale = MAX_BL_SCALE_LEVEL; else @@ -541,10 +557,31 @@ static int _sde_connector_update_bl_scale(struct sde_connector *c_conn) bl_config->bl_level); rc = c_conn->ops.set_backlight(&c_conn->base, dsi_display, bl_config->bl_level); + c_conn->unset_bl_level = 0; return rc; } +void sde_connector_set_qsync_params(struct drm_connector *connector) +{ + struct sde_connector *c_conn = to_sde_connector(connector); + u32 qsync_propval; + + if (!connector) + return; + + c_conn->qsync_updated = false; + qsync_propval = sde_connector_get_property(c_conn->base.state, + CONNECTOR_PROP_QSYNC_MODE); + + if (qsync_propval != c_conn->qsync_mode) { + SDE_DEBUG("updated qsync mode %d -> %d\n", c_conn->qsync_mode, + qsync_propval); + c_conn->qsync_updated = true; + c_conn->qsync_mode = qsync_propval; + } +} + static int _sde_connector_update_dirty_properties( struct drm_connector *connector) { @@ -559,7 +596,6 @@ static int _sde_connector_update_dirty_properties( c_conn = to_sde_connector(connector); c_state = to_sde_connector_state(connector->state); - c_conn->qsync_updated = false; while ((idx = msm_property_pop_dirty(&c_conn->property_info, &c_state->property_state)) >= 0) { @@ -575,19 +611,17 @@ static int _sde_connector_update_dirty_properties( case CONNECTOR_PROP_AD_BL_SCALE: _sde_connector_update_bl_scale(c_conn); break; - case CONNECTOR_PROP_QSYNC_MODE: - c_conn->qsync_updated = true; - c_conn->qsync_mode = sde_connector_get_property( - connector->state, CONNECTOR_PROP_QSYNC_MODE); - break; default: /* nothing to do for most properties */ break; } } - /* Special handling for postproc properties */ - if (c_conn->bl_scale_dirty) { + /* + * Special handling for postproc properties and + * for updating backlight if any unset backlight level is present + */ + if (c_conn->bl_scale_dirty || c_conn->unset_bl_level) { _sde_connector_update_bl_scale(c_conn); c_conn->bl_scale_dirty = false; } @@ -660,29 +694,44 @@ void sde_connector_helper_bridge_disable(struct drm_connector *connector) sde_connector_schedule_status_work(connector, false); c_conn = to_sde_connector(connector); - if (c_conn->panel_dead) { + if (c_conn->bl_device) { c_conn->bl_device->props.power = FB_BLANK_POWERDOWN; c_conn->bl_device->props.state |= BL_CORE_FBBLANK; backlight_update_status(c_conn->bl_device); } + + c_conn->allow_bl_update = false; } void sde_connector_helper_bridge_enable(struct drm_connector *connector) { struct sde_connector *c_conn = NULL; + struct dsi_display *display; if (!connector) return; c_conn = to_sde_connector(connector); + display = (struct dsi_display *) c_conn->display; + + /* + * Special handling for some panels which need atleast + * one frame to be transferred to GRAM before enabling backlight. + * So delay backlight update to these panels until the + * first frame commit is received from the HW. + */ + if (display->panel->bl_config.bl_update == + BL_UPDATE_DELAY_UNTIL_FIRST_FRAME) + sde_encoder_wait_for_event(c_conn->encoder, + MSM_ENC_TX_COMPLETE); + c_conn->allow_bl_update = true; - /* Special handling for ESD recovery case */ - if (c_conn->panel_dead) { + if (c_conn->bl_device) { c_conn->bl_device->props.power = FB_BLANK_UNBLANK; c_conn->bl_device->props.state &= ~BL_CORE_FBBLANK; backlight_update_status(c_conn->bl_device); - c_conn->panel_dead = false; } + c_conn->panel_dead = false; } int sde_connector_clk_ctrl(struct drm_connector *connector, bool enable) @@ -2239,15 +2288,12 @@ struct drm_connector *sde_connector_init(struct drm_device *dev, 0x0, 0, AUTOREFRESH_MAX_FRAME_CNT, 0, CONNECTOR_PROP_AUTOREFRESH); - if (connector_type == DRM_MODE_CONNECTOR_DSI) { - if (sde_kms->catalog->has_qsync && display_info.qsync_min_fps) { - - msm_property_install_enum(&c_conn->property_info, - "qsync_mode", 0, 0, e_qsync_mode, - ARRAY_SIZE(e_qsync_mode), - CONNECTOR_PROP_QSYNC_MODE); - } - } + if (connector_type == DRM_MODE_CONNECTOR_DSI && + sde_kms->catalog->has_qsync && + display_info.qsync_min_fps) + msm_property_install_enum(&c_conn->property_info, "qsync_mode", + 0, 0, e_qsync_mode, ARRAY_SIZE(e_qsync_mode), + CONNECTOR_PROP_QSYNC_MODE); msm_property_install_range(&c_conn->property_info, "bl_scale", 0x0, 0, MAX_BL_SCALE_LEVEL, MAX_BL_SCALE_LEVEL, diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h index 53ac07945f84ed80b7e22f2debfac0245f8acbda..fe3ff86054dad6f66b756d9f870c9f23e01e39ee 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.h +++ b/drivers/gpu/drm/msm/sde/sde_connector.h @@ -373,7 +373,9 @@ struct sde_connector_evt { * @bl_scale_dirty: Flag to indicate PP BL scale value(s) is changed * @bl_scale: BL scale value for ABA feature * @bl_scale_ad: BL scale value for AD feature - * @qsync_mode: Qsync mode, where 0: disabled 1: continuous mode + * @unset_bl_level: BL level that needs to be set later + * @allow_bl_update: Flag to indicate if BL update is allowed currently or not + * @qsync_mode: Cached Qsync mode, 0=disabled, 1=continuous mode * @qsync_updated: Qsync settings were updated * last_cmd_tx_sts: status of the last command transfer */ @@ -420,6 +422,8 @@ struct sde_connector { bool bl_scale_dirty; u32 bl_scale; u32 bl_scale_ad; + u32 unset_bl_level; + bool allow_bl_update; u32 qsync_mode; bool qsync_updated; @@ -459,13 +463,22 @@ struct sde_connector { ((C) ? to_sde_connector((C))->encoder : NULL) /** - * sde_connector_qsync_updated - indicates if connector updated qsync + * sde_connector_is_qsync_updated - indicates if qsync mode changed on this + * connector for the current frame update. * @C: Pointer to drm connector structure - * Returns: True if qsync is updated; false otherwise + * Returns: True if qsync mode is updated; false otherwise */ -#define sde_connector_qsync_updated(C) \ +#define sde_connector_is_qsync_updated(C) \ ((C) ? to_sde_connector((C))->qsync_updated : 0) +/** + * sde_connector_get_qsync_mode - get sde connector's qsync_mode + * @C: Pointer to drm connector structure + * Returns: Current cached qsync_mode for given connector + */ +#define sde_connector_get_qsync_mode(C) \ + ((C) ? to_sde_connector((C))->qsync_mode : 0) + /** * sde_connector_get_propinfo - get sde connector's property info pointer * @C: Pointer to drm connector structure @@ -679,6 +692,17 @@ int sde_connector_clk_ctrl(struct drm_connector *connector, bool enable); */ int sde_connector_get_dpms(struct drm_connector *connector); +/** + * sde_connector_set_qsync_params - set status of qsync_updated for current + * frame and update the cached qsync_mode + * @connector: pointer to drm connector + * + * This must be called after the connector set_property values are applied, + * and before sde_connector's qsync_updated or qsync_mode fields are accessed. + * It must only be called once per frame update for the given connector. + */ +void sde_connector_set_qsync_params(struct drm_connector *connector); + /** * sde_connector_trigger_event - indicate that an event has occurred * Any callbacks that have been registered against this event will diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index 6ffb3ac01ad443a17cc3994af2b34ea932f839e4..4dd29f81bfd3a89f6d61239941b5f44967786362 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -177,6 +177,7 @@ enum sde_enc_rc_states { * @hw_pp Handle to the pingpong blocks used for the display. No. * pingpong blocks can be different than num_phys_encs. * @hw_dsc: Array of DSC block handles used for the display. + * @dirty_dsc_ids: Cached dsc indexes for dirty DSC blocks needing flush * @intfs_swapped Whether or not the phys_enc interfaces have been swapped * for partial update right-only cases, such as pingpong * split where virtual pingpong does not generate IRQs @@ -236,6 +237,7 @@ struct sde_encoder_virt { struct sde_encoder_phys *cur_master; struct sde_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC]; struct sde_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC]; + enum sde_dsc dirty_dsc_ids[MAX_CHANNELS_PER_ENC]; bool intfs_swapped; @@ -957,7 +959,7 @@ static int sde_encoder_virt_atomic_check( } } - if (!ret && drm_atomic_crtc_needs_modeset(crtc_state)) { + if (!ret && (crtc_state->mode_changed || crtc_state->active_changed)) { struct sde_rect mode_roi, roi; mode_roi.x = 0; @@ -1139,25 +1141,37 @@ static void _sde_encoder_dsc_pclk_param_calc(struct msm_display_dsc_info *dsc, static int _sde_encoder_dsc_initial_line_calc(struct msm_display_dsc_info *dsc, int enc_ip_width) { - int ssm_delay, total_pixels, soft_slice_per_enc; + int ssm_delay, total_pixels, soft_slice_per_enc, fifo_size; + int first_line_offset, tmp[3]; soft_slice_per_enc = enc_ip_width / dsc->slice_width; /* * minimum number of initial line pixels is a sum of: - * 1. sub-stream multiplexer delay (83 groups for 8bpc, - * 91 for 10 bpc) * 3 + * 1. sub-stream multiplexer delay (84 groups for 8bpc, + * 92 for 10 bpc) * 3 * 2. for two soft slice cases, add extra sub-stream multiplexer * 3 * 3. the initial xmit delay * 4. total pipeline delay through the "lock step" of encoder (47) * 5. 6 additional pixels as the output of the rate buffer is * 48 bits wide */ - ssm_delay = ((dsc->bpc < 10) ? 84 : 92); - total_pixels = ssm_delay * 3 + dsc->initial_xmit_delay + 47; - if (soft_slice_per_enc > 1) - total_pixels += (ssm_delay * 3); + ssm_delay = 3 * ((dsc->bpc < 10) ? 84 : 92); + total_pixels = (soft_slice_per_enc * ssm_delay) + + dsc->initial_xmit_delay + 47; + fifo_size = ((soft_slice_per_enc == 2) ? 5610 : 11610); + first_line_offset = + (dsc->first_line_bpg_offset * dsc->pic_width) / (3 * 8); + dsc->initial_lines = DIV_ROUND_UP(total_pixels, dsc->slice_width); + + tmp[0] = dsc->initial_xmit_delay + first_line_offset; + tmp[1] = (2 + (0.75 * soft_slice_per_enc)) * dsc->chunk_size; + tmp[2] = (total_pixels % dsc->slice_width) * (dsc->bpp / 8); + + if ((tmp[0] + tmp[1] - tmp[2]) < fifo_size) + dsc->initial_lines++; + return 0; } @@ -1188,8 +1202,20 @@ static void _sde_encoder_dsc_pipe_cfg(struct sde_hw_dsc *hw_dsc, u32 common_mode, bool ich_reset, bool enable) { if (!enable) { - if (hw_pp->ops.disable_dsc) + if (hw_pp && hw_pp->ops.disable_dsc) hw_pp->ops.disable_dsc(hw_pp); + + if (hw_dsc && hw_dsc->ops.dsc_disable) + hw_dsc->ops.dsc_disable(hw_dsc); + + if (hw_dsc && hw_dsc->ops.bind_pingpong_blk) + hw_dsc->ops.bind_pingpong_blk(hw_dsc, false, + PINGPONG_MAX); + return; + } + + if (!dsc || !hw_dsc || !hw_pp) { + SDE_ERROR("invalid params %d %d %d\n", !dsc, !hw_dsc, !hw_pp); return; } @@ -1279,10 +1305,6 @@ static int _sde_encoder_dsc_n_lm_1_enc_1_intf(struct sde_encoder_virt *sde_enc) _sde_encoder_dsc_pipe_cfg(hw_dsc, hw_pp, dsc, dsc_common_mode, ich_res, true); - if (cfg.dsc_count >= MAX_DSC_PER_CTL_V1) { - pr_err("Invalid dsc count:%d\n", cfg.dsc_count); - return -EINVAL; - } cfg.dsc[cfg.dsc_count++] = hw_dsc->idx; /* setup dsc active configuration in the control path */ @@ -1402,8 +1424,7 @@ static int _sde_encoder_dsc_2_lm_2_enc_2_intf(struct sde_encoder_virt *sde_enc, cfg.dsc_count); return -EINVAL; } - cfg.dsc[i] = hw_dsc[i]->idx; - cfg.dsc_count++; + cfg.dsc[cfg.dsc_count++] = hw_dsc[i]->idx; if (hw_ctl->ops.update_bitmask_dsc) hw_ctl->ops.update_bitmask_dsc(hw_ctl, @@ -1713,32 +1734,47 @@ static void _sde_encoder_update_vsync_source(struct sde_encoder_virt *sde_enc, } } -static int _sde_encoder_dsc_disable(struct sde_encoder_virt *sde_enc) +static void _sde_encoder_dsc_disable(struct sde_encoder_virt *sde_enc) { - int i, ret = 0; + int i; struct sde_hw_pingpong *hw_pp = NULL; struct sde_hw_dsc *hw_dsc = NULL; + struct sde_hw_ctl *hw_ctl = NULL; + struct sde_ctl_dsc_cfg cfg; if (!sde_enc || !sde_enc->phys_encs[0] || !sde_enc->phys_encs[0]->connector) { SDE_ERROR("invalid params %d %d\n", !sde_enc, sde_enc ? !sde_enc->phys_encs[0] : -1); - return -EINVAL; + return; } + if (sde_enc->cur_master) + hw_ctl = sde_enc->cur_master->hw_ctl; + /* Disable DSC for all the pp's present in this topology */ for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) { hw_pp = sde_enc->hw_pp[i]; hw_dsc = sde_enc->hw_dsc[i]; - if (hw_pp && hw_pp->ops.disable_dsc) - hw_pp->ops.disable_dsc(hw_pp); + _sde_encoder_dsc_pipe_cfg(hw_dsc, hw_pp, NULL, 0, 0, 0); - if (hw_dsc && hw_dsc->ops.dsc_disable) - hw_dsc->ops.dsc_disable(hw_dsc); + if (hw_dsc) + sde_enc->dirty_dsc_ids[i] = hw_dsc->idx; } - return ret; + /* Clear the DSC ACTIVE config for this CTL */ + if (hw_ctl && hw_ctl->ops.setup_dsc_cfg) { + memset(&cfg, 0, sizeof(cfg)); + hw_ctl->ops.setup_dsc_cfg(hw_ctl, &cfg); + } + + /** + * Since pending flushes from previous commit get cleared + * sometime after this point, setting DSC flush bits now + * will have no effect. Therefore dirty_dsc_ids track which + * DSC blocks must be flushed for the next trigger. + */ } static int _sde_encoder_switch_to_watchdog_vsync(struct drm_encoder *drm_enc) @@ -1780,8 +1816,7 @@ static int _sde_encoder_update_rsc_client( struct drm_crtc *primary_crtc; int pipe = -1; int rc = 0; - int wait_refcount, i; - struct sde_encoder_phys *phys; + int wait_refcount; u32 qsync_mode = 0; if (!drm_enc || !drm_enc->dev) { @@ -1816,16 +1851,9 @@ static int _sde_encoder_update_rsc_client( * secondary command mode panel. * Clone mode encoder can request CLK STATE only. */ - for (i = 0; i < sde_enc->num_phys_encs; i++) { - phys = sde_enc->phys_encs[i]; - - if (phys) { - qsync_mode = sde_connector_get_property( - phys->connector->state, - CONNECTOR_PROP_QSYNC_MODE); - break; - } - } + if (sde_enc->cur_master) + qsync_mode = sde_connector_get_qsync_mode( + sde_enc->cur_master->connector); if (sde_encoder_in_clone_mode(drm_enc)) rsc_state = enable ? SDE_RSC_CLK_STATE : SDE_RSC_IDLE_STATE; @@ -3240,11 +3268,11 @@ void sde_encoder_helper_phys_disable(struct sde_encoder_phys *phys_enc, sde_enc = to_sde_encoder_virt(phys_enc->parent); if (phys_enc == sde_enc->cur_master && phys_enc->hw_pp && - phys_enc->hw_pp->merge_3d && phys_enc->hw_ctl->ops.reset_post_disable) phys_enc->hw_ctl->ops.reset_post_disable( phys_enc->hw_ctl, &phys_enc->intf_cfg_v1, - phys_enc->hw_pp->merge_3d->idx); + phys_enc->hw_pp->merge_3d ? + phys_enc->hw_pp->merge_3d->idx : 0); phys_enc->hw_ctl->ops.trigger_flush(phys_enc->hw_ctl); phys_enc->hw_ctl->ops.trigger_start(phys_enc->hw_ctl); @@ -4343,6 +4371,40 @@ static int _helper_flush_qsync(struct sde_encoder_phys *phys_enc) return 0; } +static bool _sde_encoder_dsc_is_dirty(struct sde_encoder_virt *sde_enc) +{ + int i; + + for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) { + /** + * This dirty_dsc_hw field is set during DSC disable to + * indicate which DSC blocks need to be flushed + */ + if (sde_enc->dirty_dsc_ids[i]) + return true; + } + + return false; +} + +static void _helper_flush_dsc(struct sde_encoder_virt *sde_enc) +{ + int i; + struct sde_hw_ctl *hw_ctl = NULL; + enum sde_dsc dsc_idx; + + if (sde_enc->cur_master) + hw_ctl = sde_enc->cur_master->hw_ctl; + + for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) { + dsc_idx = sde_enc->dirty_dsc_ids[i]; + if (dsc_idx && hw_ctl && hw_ctl->ops.update_bitmask_dsc) + hw_ctl->ops.update_bitmask_dsc(hw_ctl, dsc_idx, 1); + + sde_enc->dirty_dsc_ids[i] = DSC_NONE; + } +} + int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, struct sde_encoder_kickoff_params *params) { @@ -4376,6 +4438,11 @@ int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, else ln_cnt1 = -EINVAL; + /* update the qsync parameters for the current frame */ + if (sde_enc->cur_master) + sde_connector_set_qsync_params( + sde_enc->cur_master->connector); + /* prepare for next kickoff, may include waiting on previous kickoff */ SDE_ATRACE_BEGIN("sde_encoder_prepare_for_kickoff"); for (i = 0; i < sde_enc->num_phys_encs; i++) { @@ -4392,8 +4459,8 @@ int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, needs_hw_reset = true; _sde_encoder_setup_dither(phys); - /* flush the mixer if qsync is enabled */ - if (sde_enc->cur_master && sde_connector_qsync_updated( + if (sde_enc->cur_master && + sde_connector_is_qsync_updated( sde_enc->cur_master->connector)) { _helper_flush_qsync(phys); } @@ -4447,6 +4514,8 @@ int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, SDE_ERROR_ENC(sde_enc, "failed to setup DSC: %d\n", rc); ret = rc; } + } else if (_sde_encoder_dsc_is_dirty(sde_enc)) { + _helper_flush_dsc(sde_enc); } end: diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c index ba92fa37c4210f2d6481162c3f34995e083038e7..405d28f5ed2e4e5d105679c0e3bd77986f1dd8fc 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c @@ -131,7 +131,6 @@ static void _sde_encoder_phys_cmd_update_flush_mask( { struct sde_encoder_phys_cmd *cmd_enc; struct sde_hw_ctl *ctl; - bool merge_3d_enable = false; if (!phys_enc || !phys_enc->hw_intf || !phys_enc->hw_pp) return; @@ -149,16 +148,11 @@ static void _sde_encoder_phys_cmd_update_flush_mask( return; } - if (sde_encoder_helper_get_3d_blend_mode(phys_enc) != BLEND_3D_NONE) - merge_3d_enable = true; - ctl->ops.update_bitmask_intf(ctl, phys_enc->intf_idx, 1); - - if (test_bit(SDE_CTL_ACTIVE_CFG, &ctl->caps->features) && - phys_enc->hw_pp->merge_3d) + if (ctl->ops.update_bitmask_merge3d && phys_enc->hw_pp->merge_3d) ctl->ops.update_bitmask_merge3d(ctl, - phys_enc->hw_pp->merge_3d->idx, merge_3d_enable); + phys_enc->hw_pp->merge_3d->idx, 1); SDE_DEBUG_CMDENC(cmd_enc, "update pending flush ctl %d intf_idx %x\n", ctl->idx - CTL_0, phys_enc->intf_idx); @@ -521,6 +515,7 @@ static int _sde_encoder_phys_cmd_handle_ppdone_timeout( u32 frame_event = SDE_ENCODER_FRAME_EVENT_ERROR | SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE; struct drm_connector *conn; + struct sde_connector *sde_conn; int event; u32 pending_kickoff_cnt; @@ -528,6 +523,7 @@ static int _sde_encoder_phys_cmd_handle_ppdone_timeout( return -EINVAL; conn = phys_enc->connector; + sde_conn = to_sde_connector(conn); cmd_enc->pp_timeout_report_cnt++; pending_kickoff_cnt = atomic_read(&phys_enc->pending_kickoff_cnt); @@ -551,7 +547,8 @@ static int _sde_encoder_phys_cmd_handle_ppdone_timeout( atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0); /* check if panel is still sending TE signal or not */ - if (sde_connector_esd_status(phys_enc->connector)) + if (sde_connector_esd_status(phys_enc->connector) || + sde_conn->panel_dead) goto exit; /* to avoid flooding, only log first time, and "dead" time */ @@ -910,8 +907,7 @@ static int _get_tearcheck_threshold(struct sde_encoder_phys *phys_enc, return 0; mode = &phys_enc->cached_mode; - qsync_mode = sde_connector_get_property( - conn->state, CONNECTOR_PROP_QSYNC_MODE); + qsync_mode = sde_connector_get_qsync_mode(conn); if (mode && (qsync_mode == SDE_RM_QSYNC_CONTINUOUS_MODE)) { u32 qsync_min_fps = 0; @@ -1369,7 +1365,7 @@ static int sde_encoder_phys_cmd_prepare_for_kickoff( SDE_ERROR("failed wait_for_idle: %d\n", ret); } - if (sde_connector_qsync_updated(phys_enc->connector)) { + if (sde_connector_is_qsync_updated(phys_enc->connector)) { tc_cfg.sync_threshold_start = _get_tearcheck_threshold(phys_enc, &extra_frame_trigger_time); diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c index b17da7bef135d15b08956fc003896a2822b05d55..ea8ca618bef4a04b4eaae7548519df58c1682d8c 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c @@ -119,6 +119,15 @@ static void drm_mode_to_intf_timing_params( timing->vsync_polarity = 0; } + /* for DP/EDP, Shift timings to align it to bottom right */ + if ((phys_enc->hw_intf->cap->type == INTF_DP) || + (phys_enc->hw_intf->cap->type == INTF_EDP)) { + timing->h_back_porch += timing->h_front_porch; + timing->h_front_porch = 0; + timing->v_back_porch += timing->v_front_porch; + timing->v_front_porch = 0; + } + timing->wide_bus_en = vid_enc->base.wide_bus_en; /* @@ -410,9 +419,8 @@ static void _sde_encoder_phys_vid_avr_ctrl(struct sde_encoder_phys *phys_enc) struct sde_encoder_phys_vid *vid_enc = to_sde_encoder_phys_vid(phys_enc); - avr_params.avr_mode = sde_connector_get_property( - phys_enc->connector->state, - CONNECTOR_PROP_QSYNC_MODE); + avr_params.avr_mode = sde_connector_get_qsync_mode( + phys_enc->connector); if (vid_enc->base.hw_intf->ops.avr_ctrl) { vid_enc->base.hw_intf->ops.avr_ctrl( @@ -503,7 +511,8 @@ static void sde_encoder_phys_vid_setup_timing_engine( &intf_cfg); } spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); - programmable_fetch_config(phys_enc, &timing_params); + if (phys_enc->hw_intf->cap->type == INTF_DSI) + programmable_fetch_config(phys_enc, &timing_params); exit: if (phys_enc->parent_ops.get_qsync_fps) @@ -785,7 +794,6 @@ static void sde_encoder_phys_vid_enable(struct sde_encoder_phys *phys_enc) struct sde_encoder_phys_vid *vid_enc; struct sde_hw_intf *intf; struct sde_hw_ctl *ctl; - bool merge_3d_enable = false; if (!phys_enc || !phys_enc->parent || !phys_enc->parent->dev || !phys_enc->parent->dev->dev_private || @@ -846,15 +854,11 @@ static void sde_encoder_phys_vid_enable(struct sde_encoder_phys *phys_enc) goto skip_flush; } - if (sde_encoder_helper_get_3d_blend_mode(phys_enc) != BLEND_3D_NONE) - merge_3d_enable = true; - ctl->ops.update_bitmask_intf(ctl, intf->idx, 1); - if (test_bit(SDE_CTL_ACTIVE_CFG, &ctl->caps->features) && - phys_enc->hw_pp->merge_3d) + if (ctl->ops.update_bitmask_merge3d && phys_enc->hw_pp->merge_3d) ctl->ops.update_bitmask_merge3d(ctl, - phys_enc->hw_pp->merge_3d->idx, merge_3d_enable); + phys_enc->hw_pp->merge_3d->idx, 1); skip_flush: SDE_DEBUG_VIDENC(vid_enc, "update pending flush ctl %d intf %d\n", @@ -1041,7 +1045,7 @@ static int sde_encoder_phys_vid_prepare_for_kickoff( vid_enc->error_count = 0; } - if (sde_connector_qsync_updated(phys_enc->connector)) + if (sde_connector_is_qsync_updated(phys_enc->connector)) _sde_encoder_phys_vid_avr_ctrl(phys_enc); programmable_rot_fetch_config(phys_enc, @@ -1181,9 +1185,7 @@ static void sde_encoder_phys_vid_handle_post_kickoff( phys_enc->enable_state = SDE_ENC_ENABLED; } - avr_mode = sde_connector_get_property( - phys_enc->connector->state, - CONNECTOR_PROP_QSYNC_MODE); + avr_mode = sde_connector_get_qsync_mode(phys_enc->connector); if (avr_mode && vid_enc->base.hw_intf->ops.avr_trigger) { vid_enc->base.hw_intf->ops.avr_trigger(vid_enc->base.hw_intf); diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c index 2297bca67860a2ef8f001dd97a83b9a44596e549..360f332f3cc856da5f3f5ccb13a59ee831140821 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c @@ -643,6 +643,7 @@ static int _sde_enc_phys_wb_validate_cwb(struct sde_encoder_phys *phys_enc, { struct sde_crtc_state *cstate = to_sde_crtc_state(crtc_state); struct sde_rect wb_roi = {0,}; + struct sde_rect pu_roi = {0,}; int data_pt; int ds_outw = 0; int ds_outh = 0; @@ -681,12 +682,11 @@ static int _sde_enc_phys_wb_validate_cwb(struct sde_encoder_phys *phys_enc, } /* validate conn roi against pu rect */ - if (!sde_kms_rect_is_null(&cstate->crtc_roi)) { - if (wb_roi.w != cstate->crtc_roi.w || - wb_roi.h != cstate->crtc_roi.h) { + if (cstate->user_roi_list.num_rects) { + sde_kms_rect_merge_rectangles(&cstate->user_roi_list, &pu_roi); + if (wb_roi.w != pu_roi.w || wb_roi.h != pu_roi.h) { SDE_ERROR("invalid wb roi with pu [%dx%d vs %dx%d]\n", - wb_roi.w, wb_roi.h, cstate->crtc_roi.w, - cstate->crtc_roi.h); + wb_roi.w, wb_roi.h, pu_roi.w, pu_roi.h); ret = -EINVAL; goto exit; } @@ -1559,13 +1559,21 @@ static void sde_encoder_phys_wb_disable(struct sde_encoder_phys *phys_enc) if (phys_enc->hw_ctl->ops.clear_pending_flush) phys_enc->hw_ctl->ops.clear_pending_flush(phys_enc->hw_ctl); - sde_encoder_helper_phys_disable(phys_enc, wb_enc); - - phys_enc->enable_state = SDE_ENC_DISABLING; + /* + * New CTL reset sequence from 5.0 MDP onwards. + * If has_3d_merge_reset is not set, legacy reset + * sequence is executed. + */ + if (hw_wb->catalog->has_3d_merge_reset) { + sde_encoder_helper_phys_disable(phys_enc, wb_enc); + goto exit; + } - if (hw_wb->catalog->has_3d_merge_reset) + if (sde_encoder_helper_reset_mixers(phys_enc, wb_enc->fb_disable)) goto exit; + phys_enc->enable_state = SDE_ENC_DISABLING; + sde_encoder_phys_wb_prepare_for_kickoff(phys_enc, NULL); sde_encoder_phys_wb_irq_ctrl(phys_enc, true); if (phys_enc->hw_ctl->ops.trigger_flush) diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ad4.c b/drivers/gpu/drm/msm/sde/sde_hw_ad4.c index 03a251b6ea10a77a9fedc04d776042e042a3d129..285c92146de5b88ade6d6212f98edfdc1086868d 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_ad4.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_ad4.c @@ -132,7 +132,7 @@ static ad4_prop_setup prop_set_func[ad4_state_max][AD_PROPMAX] = { [ad4_state_idle][AD_ASSERTIVE] = ad4_assertive_setup, [ad4_state_idle][AD_BACKLIGHT] = ad4_backlight_setup, [ad4_state_idle][AD_STRENGTH] = ad4_strength_setup_idle, - [ad4_state_idle][AD_ROI] = ad4_no_op_setup, + [ad4_state_idle][AD_ROI] = ad4_roi_setup, [ad4_state_idle][AD_IPC_SUSPEND] = ad4_no_op_setup, [ad4_state_idle][AD_IPC_RESUME] = ad4_no_op_setup, [ad4_state_idle][AD_IPC_RESET] = ad4_no_op_setup, @@ -197,7 +197,7 @@ static ad4_prop_setup prop_set_func[ad4_state_max][AD_PROPMAX] = { [ad4_state_manual][AD_ASSERTIVE] = ad4_no_op_setup, [ad4_state_manual][AD_BACKLIGHT] = ad4_no_op_setup, [ad4_state_manual][AD_STRENGTH] = ad4_strength_setup, - [ad4_state_manual][AD_ROI] = ad4_no_op_setup, + [ad4_state_manual][AD_ROI] = ad4_roi_setup, [ad4_state_manual][AD_IPC_SUSPEND] = ad4_no_op_setup, [ad4_state_manual][AD_IPC_RESUME] = ad4_no_op_setup, [ad4_state_manual][AD_IPC_RESET] = ad4_setup_debug_manual, @@ -360,7 +360,7 @@ static int ad4_setup_debug(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg) static int ad4_setup_debug_manual(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg) { - u32 strength = 0; + u32 in_str = 0, out_str = 0; struct sde_hw_mixer *hw_lm; hw_lm = cfg->hw_cfg->mixer_info; @@ -368,8 +368,10 @@ static int ad4_setup_debug_manual(struct sde_hw_dspp *dspp, /* this AD core is the salve core */ return 0; - strength = SDE_REG_READ(&dspp->hw, dspp->cap->sblk->ad.base + 0x15c); - pr_debug("%s(): AD strength = %d in manual mode\n", __func__, strength); + in_str = SDE_REG_READ(&dspp->hw, dspp->cap->sblk->ad.base + 0x15c); + out_str = SDE_REG_READ(&dspp->hw, dspp->cap->sblk->ad.base + 0x160); + pr_debug("%s(): AD in strength = %d, out strength = %d in manual mode\n", + __func__, in_str, out_str); return 0; } @@ -1728,24 +1730,33 @@ static int ad4_ipc_reset_setup_startup(struct sde_hw_dspp *dspp, static int ad4_strength_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg) { - u64 strength = 0, val; + u64 in_str = 0, out_str = 0, val; u32 blk_offset = 0x15c; + struct drm_msm_ad4_manual_str_cfg *str_cfg = NULL; - if (cfg->hw_cfg->len != sizeof(u64) && cfg->hw_cfg->payload) { + if (cfg->hw_cfg->payload && (cfg->hw_cfg->len != + sizeof(struct drm_msm_ad4_manual_str_cfg))) { DRM_ERROR("invalid sz param exp %zd given %d cfg %pK\n", - sizeof(u64), cfg->hw_cfg->len, cfg->hw_cfg->payload); + sizeof(struct drm_msm_ad4_manual_str_cfg), + cfg->hw_cfg->len, cfg->hw_cfg->payload); return -EINVAL; } - if (cfg->hw_cfg->payload) - strength = *((u64 *)cfg->hw_cfg->payload); - else - strength = 0; + if (cfg->hw_cfg->payload) { + str_cfg = (struct drm_msm_ad4_manual_str_cfg *) + cfg->hw_cfg->payload; + in_str = str_cfg->in_str; + out_str = str_cfg->out_str; + } /* set manual strength */ info[dspp->idx].completed_ops_mask |= ad4_strength; - val = (strength & (BIT(10) - 1)); + val = (in_str & (BIT(10) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + blk_offset += 4; + val = (out_str & (BIT(10) - 1)); SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + return 0; } diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c index 1007702196a6ce06a9413e05aa77fd47353676bf..36626dad7871c5ea301ba4e3c3d47bd32af9a804 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c @@ -3522,6 +3522,10 @@ static int sde_hardware_format_caps(struct sde_mdss_cfg *sde_cfg, IS_SDE_MAJOR_SAME((hw_rev), SDE_HW_VER_500)) sde_cfg->has_hdr = true; + /* Disable HDR for SM6150 target only */ + if (IS_SDE_MAJOR_MINOR_SAME((hw_rev), SDE_HW_VER_530)) + sde_cfg->has_hdr = false; + index = sde_copy_formats(sde_cfg->dma_formats, dma_list_size, 0, plane_formats, ARRAY_SIZE(plane_formats)); index += sde_copy_formats(sde_cfg->dma_formats, dma_list_size, @@ -3622,7 +3626,21 @@ static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev) sde_cfg->delay_prg_fetch_start = true; sde_cfg->sui_ns_allowed = true; sde_cfg->sui_misr_supported = true; - sde_cfg->sui_block_xin_mask = 0x2EE1; + sde_cfg->sui_block_xin_mask = 0x2E61; + sde_cfg->has_3d_merge_reset = true; + } else if (IS_SDMMAGPIE_TARGET(hw_rev)) { + sde_cfg->has_cwb_support = true; + sde_cfg->has_wb_ubwc = true; + sde_cfg->has_qsync = true; + sde_cfg->perf.min_prefill_lines = 24; + sde_cfg->vbif_qos_nlvl = 8; + sde_cfg->ts_prefill_rev = 2; + sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0; + sde_cfg->delay_prg_fetch_start = true; + sde_cfg->sui_ns_allowed = true; + sde_cfg->sui_misr_supported = true; + sde_cfg->sui_block_xin_mask = 0xE71; + sde_cfg->has_3d_merge_reset = true; } else { SDE_ERROR("unsupported chipset id:%X\n", hw_rev); sde_cfg->perf.min_prefill_lines = 0xffff; @@ -3641,7 +3659,8 @@ static int _sde_hardware_post_caps(struct sde_mdss_cfg *sde_cfg, if (!sde_cfg) return -EINVAL; - if (IS_SM8150_TARGET(hw_rev) || IS_SM6150_TARGET(hw_rev)) { + if (IS_SM8150_TARGET(hw_rev) || IS_SM6150_TARGET(hw_rev) || + IS_SDMMAGPIE_TARGET(hw_rev)) { sde_cfg->sui_supported_blendstage = sde_cfg->max_mixer_blendstages - SDE_STAGE_0; diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h index ffe540d99c77858163be2d5d66ae49fe7723a850..f1430fd5244a5b0c53cbcaadbf2ecef6dab072d6 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h @@ -53,6 +53,7 @@ #define SDE_HW_VER_500 SDE_HW_VER(5, 0, 0) /* sm8150 v1.0 */ #define SDE_HW_VER_501 SDE_HW_VER(5, 0, 1) /* sm8150 v2.0 */ #define SDE_HW_VER_510 SDE_HW_VER(5, 1, 0) /* sdmshrike v1.0 */ +#define SDE_HW_VER_520 SDE_HW_VER(5, 2, 0) /* sdmmagpie v1.0 */ #define SDE_HW_VER_530 SDE_HW_VER(5, 3, 0) /* sm6150 v1.0 */ #define IS_MSM8996_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_170) @@ -61,6 +62,7 @@ #define IS_SDM670_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_410) #define IS_SM8150_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_500) #define IS_SDMSHRIKE_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_510) +#define IS_SDMMAGPIE_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_520) #define IS_SM6150_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_530) #define SDE_HW_BLK_NAME_LEN 16 diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c index acb50b86e0232d0daa644e77a335cd23826bf2de..bcef05e62190cced59c2f3649de71adcb06bc468 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c @@ -1054,17 +1054,19 @@ static int sde_hw_ctl_reset_post_disable(struct sde_hw_ctl *ctx, } } - /* disable and flush merge3d_blk */ - merge_3d_flush = BIT(merge_3d_idx - MERGE_3D_0); - merge_3d_active &= ~BIT(merge_3d_idx - MERGE_3D_0); - + if (merge_3d_idx) { + /* disable and flush merge3d_blk */ + merge_3d_flush = BIT(merge_3d_idx - MERGE_3D_0); + merge_3d_active &= ~BIT(merge_3d_idx - MERGE_3D_0); + ctx->flush.pending_merge_3d_flush_mask = merge_3d_flush; + SDE_REG_WRITE(c, CTL_MERGE_3D_ACTIVE, merge_3d_active); + } sde_hw_ctl_clear_all_blendstages(ctx); - ctx->flush.pending_merge_3d_flush_mask = merge_3d_flush; ctx->flush.pending_intf_flush_mask = intf_flush; ctx->flush.pending_wb_flush_mask = wb_flush; - SDE_REG_WRITE(c, CTL_MERGE_3D_ACTIVE, merge_3d_active); + SDE_REG_WRITE(c, CTL_INTF_ACTIVE, intf_active); SDE_REG_WRITE(c, CTL_WB_ACTIVE, wb_active); diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dsc.c b/drivers/gpu/drm/msm/sde/sde_hw_dsc.c index dd0a7e055b356eb23080eb50201b55b4cd90da28..c485d5e832a6793974b06d5289c08a7b0c8a41f8 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_dsc.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_dsc.c @@ -56,7 +56,6 @@ static void sde_hw_dsc_config(struct sde_hw_dsc *hw_dsc, u32 data; int bpp, lsb; u32 initial_lines = dsc->initial_lines; - bool is_cmd_mode = !(mode & BIT(2)); struct sde_hw_blk_reg_map *dsc_c = &hw_dsc->hw; SDE_REG_WRITE(dsc_c, DSC_COMMON_MODE, mode); @@ -65,9 +64,6 @@ static void sde_hw_dsc_config(struct sde_hw_dsc *hw_dsc, if (ich_reset_override) data = 3 << 28; - if (is_cmd_mode) - initial_lines += 1; - data |= (initial_lines << 20); data |= (dsc->slice_last_group_size << 18); /* bpp is 6.4 format, 4 LSBs bits are for fractional part */ diff --git a/drivers/gpu/drm/msm/sde/sde_hw_lm.c b/drivers/gpu/drm/msm/sde/sde_hw_lm.c index 7022c8e28faf703c2382c1ec56fcd55483f4b5ff..3593fe3e91cbeac4cf3ffb82d74a23b97639101e 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_lm.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_lm.c @@ -265,7 +265,8 @@ static void _setup_mixer_ops(struct sde_mdss_cfg *m, if (IS_SDM845_TARGET(m->hwversion) || IS_SDM670_TARGET(m->hwversion) || IS_SM8150_TARGET(m->hwversion) || IS_SDMSHRIKE_TARGET(m->hwversion) || - IS_SM6150_TARGET(m->hwversion)) + IS_SM6150_TARGET(m->hwversion) || + IS_SDMMAGPIE_TARGET(m->hwversion)) ops->setup_blend_config = sde_hw_lm_setup_blend_config_sdm845; else ops->setup_blend_config = sde_hw_lm_setup_blend_config; diff --git a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c index 7a40926ac7e2e72b2471c9a224f148c2b286dab5..e50088ebd9012d2da62232ab592f8ba1865eddde 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_pingpong.c @@ -495,9 +495,10 @@ static void _setup_pingpong_ops(struct sde_hw_pingpong_ops *ops, ops->setup_dither = NULL; break; } - if (test_bit(SDE_PINGPONG_MERGE_3D, &hw_cap->features)) + if (test_bit(SDE_PINGPONG_MERGE_3D, &hw_cap->features)) { ops->setup_3d_mode = sde_hw_pp_setup_3d_merge_mode; ops->reset_3d_mode = sde_hw_pp_reset_3d_merge_mode; + } }; static struct sde_hw_blk_ops sde_hw_ops = { diff --git a/drivers/gpu/drm/msm/sde/sde_hw_util.c b/drivers/gpu/drm/msm/sde/sde_hw_util.c index 4419f8054eece84efaf4d47eb022858099730dfc..535a5f3f4c77c01d974ea5c525a25fa406f8fdaf 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_util.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_util.c @@ -59,6 +59,8 @@ static u32 sde_hw_util_log_mask = SDE_DBG_MASK_NONE; /* SDE_SCALER_QSEED3LITE */ #define QSEED3L_COEF_LUT_Y_SEP_BIT 4 #define QSEED3L_COEF_LUT_UV_SEP_BIT 5 +#define QSEED3L_COEF_LUT_CTRL 0x4C +#define QSEED3L_COEF_LUT_SWAP_BIT 0 #define QSEED3L_DIR_FILTER_WEIGHT 0x60 #define QSEED3LITE_SCALER_VERSION 0x2004 @@ -264,6 +266,9 @@ static void _sde_hw_setup_scaler3lite_lut(struct sde_hw_blk_reg_map *c, } } } + + if (test_bit(QSEED3L_COEF_LUT_SWAP_BIT, &lut_flags)) + SDE_REG_WRITE(c, QSEED3L_COEF_LUT_CTRL + offset, BIT(0)); } static void _sde_hw_setup_scaler3_de(struct sde_hw_blk_reg_map *c, diff --git a/drivers/gpu/drm/msm/sde/sde_hw_vbif.c b/drivers/gpu/drm/msm/sde/sde_hw_vbif.c index ed1e44b84f34e6f5d338fdf4fa8e62095bf19898..3bbb5ce038e496db7ab68e2dd9f9bd9a20316285 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_vbif.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_vbif.c @@ -241,7 +241,8 @@ static void _setup_vbif_ops(const struct sde_mdss_cfg *m, ops->get_halt_ctrl = sde_hw_get_halt_ctrl; if (test_bit(SDE_VBIF_QOS_REMAP, &cap)) ops->set_qos_remap = sde_hw_set_qos_remap; - if (IS_SM8150_TARGET(m->hwversion) || IS_SM6150_TARGET(m->hwversion)) + if (IS_SM8150_TARGET(m->hwversion) || IS_SM6150_TARGET(m->hwversion) || + IS_SDMMAGPIE_TARGET(m->hwversion)) ops->set_mem_type = sde_hw_set_mem_type_v1; else ops->set_mem_type = sde_hw_set_mem_type; diff --git a/drivers/gpu/drm/msm/sde/sde_irq.c b/drivers/gpu/drm/msm/sde/sde_irq.c index 7584942ac59189b6998e9c376fe2f4a0f58b8a74..536d666db04b9553a7be5fb846c5097c2c9b1437 100644 --- a/drivers/gpu/drm/msm/sde/sde_irq.c +++ b/drivers/gpu/drm/msm/sde/sde_irq.c @@ -19,7 +19,7 @@ #include "sde_irq.h" #include "sde_core_irq.h" -static uint32_t g_sde_irq_status; +uint32_t g_sde_irq_status; void sde_irq_update(struct msm_kms *msm_kms, bool enable) { diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c index 333f22ac52b0f721169ece0de32f806312969422..4802cddac3382f448726cbe007c88846187a00d0 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ b/drivers/gpu/drm/msm/sde/sde_kms.c @@ -2105,7 +2105,7 @@ static void sde_kms_preclose(struct msm_kms *kms, struct drm_file *file) } end: - if ((ret != 0) && state) + if (state) drm_atomic_state_put(state); SDE_DEBUG("sde preclose done, ret:%d\n", ret); @@ -2220,14 +2220,10 @@ static void sde_kms_lastclose(struct msm_kms *kms, SDE_DEBUG("deadlock backoff on attempt %d\n", i); } - if (ret) { - /** - * on success, atomic state object ownership transfers to - * framework, otherwise, free it here - */ - drm_atomic_state_put(state); + if (ret) SDE_ERROR("failed to run last close: %d\n", ret); - } + + drm_atomic_state_put(state); } static int sde_kms_check_secure_transition(struct msm_kms *kms, @@ -2650,7 +2646,7 @@ static int sde_kms_pm_suspend(struct device *dev) struct drm_modeset_acquire_ctx ctx; struct drm_connector *conn; struct drm_connector_list_iter conn_iter; - struct drm_atomic_state *state; + struct drm_atomic_state *state = NULL; struct sde_kms *sde_kms; int ret = 0, num_crtcs = 0; @@ -2680,15 +2676,17 @@ static int sde_kms_pm_suspend(struct device *dev) drm_atomic_state_put(sde_kms->suspend_state); sde_kms->suspend_state = drm_atomic_helper_duplicate_state(ddev, &ctx); if (IS_ERR_OR_NULL(sde_kms->suspend_state)) { - DRM_ERROR("failed to back up suspend state\n"); + ret = PTR_ERR(sde_kms->suspend_state); + DRM_ERROR("failed to back up suspend state, %d\n", ret); sde_kms->suspend_state = NULL; goto unlock; } /* create atomic state to disable all CRTCs */ state = drm_atomic_state_alloc(ddev); - if (IS_ERR_OR_NULL(state)) { - DRM_ERROR("failed to allocate crtc disable state\n"); + if (!state) { + ret = -ENOMEM; + DRM_ERROR("failed to allocate crtc disable state, %d\n", ret); goto unlock; } @@ -2710,7 +2708,7 @@ static int sde_kms_pm_suspend(struct device *dev) if (ret) { DRM_ERROR("failed to set lp2 for conn %d\n", conn->base.id); - drm_atomic_state_put(state); + drm_connector_list_iter_end(&conn_iter); goto unlock; } } @@ -2722,7 +2720,7 @@ static int sde_kms_pm_suspend(struct device *dev) if (IS_ERR_OR_NULL(crtc_state)) { DRM_ERROR("failed to get crtc %d state\n", conn->state->crtc->base.id); - drm_atomic_state_put(state); + drm_connector_list_iter_end(&conn_iter); goto unlock; } @@ -2736,7 +2734,6 @@ static int sde_kms_pm_suspend(struct device *dev) /* check for nothing to do */ if (num_crtcs == 0) { DRM_DEBUG("all crtcs are already in the off state\n"); - drm_atomic_state_put(state); sde_kms->suspend_block = true; goto unlock; } @@ -2745,7 +2742,6 @@ static int sde_kms_pm_suspend(struct device *dev) ret = drm_atomic_commit(state); if (ret < 0) { DRM_ERROR("failed to disable crtcs, %d\n", ret); - drm_atomic_state_put(state); goto unlock; } @@ -2770,6 +2766,11 @@ static int sde_kms_pm_suspend(struct device *dev) } drm_connector_list_iter_end(&conn_iter); unlock: + if (state) { + drm_atomic_state_put(state); + state = NULL; + } + if (ret == -EDEADLK) { drm_modeset_backoff(&ctx); goto retry; @@ -2777,7 +2778,7 @@ static int sde_kms_pm_suspend(struct device *dev) drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); - return 0; + return ret; } static int sde_kms_pm_resume(struct device *dev) @@ -2823,10 +2824,10 @@ static int sde_kms_pm_resume(struct device *dev) drm_modeset_backoff(&ctx); } - if (ret < 0) { + if (ret < 0) DRM_ERROR("failed to restore state, %d\n", ret); - drm_atomic_state_put(sde_kms->suspend_state); - } + + drm_atomic_state_put(sde_kms->suspend_state); sde_kms->suspend_state = NULL; } diff --git a/drivers/gpu/drm/msm/sde_dbg.c b/drivers/gpu/drm/msm/sde_dbg.c index 140630b1b9c7163f5c81696bfecaf1e0ae4e8009..6ad1d7059834c4a00881c4e3c0512543b1231bec 100644 --- a/drivers/gpu/drm/msm/sde_dbg.c +++ b/drivers/gpu/drm/msm/sde_dbg.c @@ -5082,7 +5082,8 @@ void sde_dbg_init_dbg_buses(u32 hwversion) ARRAY_SIZE(vbif_dbg_bus_msm8998); dbg->dbgbus_dsi.entries = dsi_dbg_bus_sdm845; dbg->dbgbus_dsi.size = ARRAY_SIZE(dsi_dbg_bus_sdm845); - } else if (IS_SM8150_TARGET(hwversion) || IS_SM6150_TARGET(hwversion)) { + } else if (IS_SM8150_TARGET(hwversion) || IS_SM6150_TARGET(hwversion) || + IS_SDMMAGPIE_TARGET(hwversion)) { dbg->dbgbus_sde.entries = dbg_bus_sde_sm8150; dbg->dbgbus_sde.cmn.entries_size = ARRAY_SIZE(dbg_bus_sde_sm8150); diff --git a/drivers/gpu/drm/msm/sde_hdcp_2x.c b/drivers/gpu/drm/msm/sde_hdcp_2x.c index 9a1f77178ce989045e515afc32101c6236b2d6e0..15f3aa008520c8abce7078f944250da3a7ef97f6 100644 --- a/drivers/gpu/drm/msm/sde_hdcp_2x.c +++ b/drivers/gpu/drm/msm/sde_hdcp_2x.c @@ -312,7 +312,6 @@ static void sde_hdcp_2x_wakeup_client(struct sde_hdcp_2x_ctrl *hdcp, static inline void sde_hdcp_2x_send_message(struct sde_hdcp_2x_ctrl *hdcp) { - char msg_name[50]; struct hdcp_transport_wakeup_data cdata = { HDCP_TRANSPORT_CMD_SEND_MESSAGE }; @@ -323,13 +322,9 @@ static inline void sde_hdcp_2x_send_message(struct sde_hdcp_2x_ctrl *hdcp) /* ignore the first byte as it contains the message id */ cdata.buf = hdcp->app_data.response.data + 1; - snprintf(msg_name, sizeof(msg_name), "%s: ", + pr_debug("%s\n", sde_hdcp_2x_message_name(hdcp->app_data.response.data[0])); - print_hex_dump(KERN_DEBUG, msg_name, - DUMP_PREFIX_NONE, 16, 1, cdata.buf, - cdata.buf_len, false); - sde_hdcp_2x_wakeup_client(hdcp, &cdata); } @@ -588,7 +583,6 @@ static void sde_hdcp_2x_msg_recvd(struct sde_hdcp_2x_ctrl *hdcp) { int rc = 0; char *msg = NULL; - char msg_name[50]; u32 message_id_bytes = 0; u32 request_length, out_msg; struct hdcp_transport_wakeup_data cdata = { @@ -616,12 +610,6 @@ static void sde_hdcp_2x_msg_recvd(struct sde_hdcp_2x_ctrl *hdcp) request_length += message_id_bytes; - snprintf(msg_name, sizeof(msg_name), "%s: ", - sde_hdcp_2x_message_name((int)msg[0])); - - print_hex_dump(KERN_DEBUG, msg_name, - DUMP_PREFIX_NONE, 16, 1, msg, request_length, false); - pr_debug("message received from SINK: %s\n", sde_hdcp_2x_message_name(msg[0])); diff --git a/drivers/gpu/drm/msm/sde_io_util.c b/drivers/gpu/drm/msm/sde_io_util.c index 4fafa63c1ba004ce095e3794a5b6a6bd8fcd9d5a..9c34e18aa53787a724b7fab58368909f3bf18a46 100644 --- a/drivers/gpu/drm/msm/sde_io_util.c +++ b/drivers/gpu/drm/msm/sde_io_util.c @@ -389,27 +389,41 @@ int msm_dss_get_clk(struct device *dev, struct dss_clk *clk_arry, int num_clk) } /* msm_dss_get_clk */ EXPORT_SYMBOL(msm_dss_get_clk); +int msm_dss_single_clk_set_rate(struct dss_clk *clk) +{ + int rc = 0; + + if (!clk) { + DEV_ERR("invalid clk struct\n"); + return -EINVAL; + } + + DEV_DBG("%pS->%s: set_rate '%s'\n", + __builtin_return_address(0), __func__, + clk->clk_name); + + if (clk->type != DSS_CLK_AHB) { + rc = clk_set_rate(clk->clk, clk->rate); + if (rc) + DEV_ERR("%pS->%s: %s failed. rc=%d\n", + __builtin_return_address(0), + __func__, + clk->clk_name, rc); + } + + return rc; +} /* msm_dss_single_clk_set_rate */ +EXPORT_SYMBOL(msm_dss_single_clk_set_rate); + int msm_dss_clk_set_rate(struct dss_clk *clk_arry, int num_clk) { int i, rc = 0; for (i = 0; i < num_clk; i++) { if (clk_arry[i].clk) { - if (clk_arry[i].type != DSS_CLK_AHB) { - DEV_DBG("%pS->%s: '%s' rate %ld\n", - __builtin_return_address(0), __func__, - clk_arry[i].clk_name, - clk_arry[i].rate); - rc = clk_set_rate(clk_arry[i].clk, - clk_arry[i].rate); - if (rc) { - DEV_ERR("%pS->%s: %s failed. rc=%d\n", - __builtin_return_address(0), - __func__, - clk_arry[i].clk_name, rc); - break; - } - } + rc = msm_dss_single_clk_set_rate(&clk_arry[i]); + if (rc) + break; } else { DEV_ERR("%pS->%s: '%s' is not available\n", __builtin_return_address(0), __func__, diff --git a/drivers/gpu/drm/msm/sde_power_handle.c b/drivers/gpu/drm/msm/sde_power_handle.c index ed31362a83eae895dd987064af07ada79f681ecf..b0627c20aacd67aaa3eeaf0a6c0ef920051ae5be 100644 --- a/drivers/gpu/drm/msm/sde_power_handle.c +++ b/drivers/gpu/drm/msm/sde_power_handle.c @@ -1137,7 +1137,7 @@ int sde_power_clk_set_rate(struct sde_power_handle *phandle, char *clock_name, sde_cx_ipeak_vote(phandle, &mp->clk_config[i], requested_clk_rate, prev_clk_rate, true); mp->clk_config[i].rate = rate; - rc = msm_dss_clk_set_rate(mp->clk_config, mp->num_clk); + rc = msm_dss_single_clk_set_rate(&mp->clk_config[i]); if (!rc) sde_cx_ipeak_vote(phandle, &mp->clk_config[i], requested_clk_rate, prev_clk_rate, false); diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 430830d63a33dcd7aad0ecf17ed40b8cd5051162..2c6d19683688623652a5c24f4dbded829b2dd441 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -570,12 +570,16 @@ nouveau_connector_detect(struct drm_connector *connector, bool force) nv_connector->edid = NULL; } - /* Outputs are only polled while runtime active, so acquiring a - * runtime PM ref here is unnecessary (and would deadlock upon - * runtime suspend because it waits for polling to finish). + /* Outputs are only polled while runtime active, so resuming the + * device here is unnecessary (and would deadlock upon runtime suspend + * because it waits for polling to finish). We do however, want to + * prevent the autosuspend timer from elapsing during this operation + * if possible. */ - if (!drm_kms_helper_is_poll_worker()) { - ret = pm_runtime_get_sync(connector->dev->dev); + if (drm_kms_helper_is_poll_worker()) { + pm_runtime_get_noresume(dev->dev); + } else { + ret = pm_runtime_get_sync(dev->dev); if (ret < 0 && ret != -EACCES) return conn_status; } @@ -653,10 +657,8 @@ nouveau_connector_detect(struct drm_connector *connector, bool force) out: - if (!drm_kms_helper_is_poll_worker()) { - pm_runtime_mark_last_busy(connector->dev->dev); - pm_runtime_put_autosuspend(connector->dev->dev); - } + pm_runtime_mark_last_busy(dev->dev); + pm_runtime_put_autosuspend(dev->dev); return conn_status; } @@ -1120,6 +1122,26 @@ nouveau_connector_hotplug(struct nvif_notify *notify) const struct nvif_notify_conn_rep_v0 *rep = notify->data; const char *name = connector->name; struct nouveau_encoder *nv_encoder; + int ret; + + ret = pm_runtime_get(drm->dev->dev); + if (ret == 0) { + /* We can't block here if there's a pending PM request + * running, as we'll deadlock nouveau_display_fini() when it + * calls nvif_put() on our nvif_notify struct. So, simply + * defer the hotplug event until the device finishes resuming + */ + NV_DEBUG(drm, "Deferring HPD on %s until runtime resume\n", + name); + schedule_work(&drm->hpd_work); + + pm_runtime_put_noidle(drm->dev->dev); + return NVIF_NOTIFY_KEEP; + } else if (ret != 1 && ret != -EACCES) { + NV_WARN(drm, "HPD on %s dropped due to RPM failure: %d\n", + name, ret); + return NVIF_NOTIFY_DROP; + } if (rep->mask & NVIF_NOTIFY_CONN_V0_IRQ) { NV_DEBUG(drm, "service %s\n", name); @@ -1137,6 +1159,8 @@ nouveau_connector_hotplug(struct nvif_notify *notify) drm_helper_hpd_irq_event(connector->dev); } + pm_runtime_mark_last_busy(drm->dev->dev); + pm_runtime_put_autosuspend(drm->dev->dev); return NVIF_NOTIFY_KEEP; } diff --git a/drivers/gpu/drm/nouveau/nouveau_debugfs.c b/drivers/gpu/drm/nouveau/nouveau_debugfs.c index 963a4dba8213eb6080ff3713cbbdbb20ddb4b61e..9109b69cd052958bbc126b4bad4f490720e11f4a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_debugfs.c +++ b/drivers/gpu/drm/nouveau/nouveau_debugfs.c @@ -160,7 +160,11 @@ nouveau_debugfs_pstate_set(struct file *file, const char __user *ubuf, args.ustate = value; } + ret = pm_runtime_get_sync(drm->dev); + if (IS_ERR_VALUE(ret) && ret != -EACCES) + return ret; ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_USER, &args, sizeof(args)); + pm_runtime_put_autosuspend(drm->dev); if (ret < 0) return ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index caf53503c0f7a5cea1265c2b333212f76e3b9014..2612702c3a3ffd8daed50a1e253b11d96c71dab9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -356,8 +356,6 @@ nouveau_display_hpd_work(struct work_struct *work) pm_runtime_get_sync(drm->dev->dev); drm_helper_hpd_irq_event(drm->dev); - /* enable polling for external displays */ - drm_kms_helper_poll_enable(drm->dev); pm_runtime_mark_last_busy(drm->dev->dev); pm_runtime_put_sync(drm->dev->dev); @@ -380,15 +378,29 @@ nouveau_display_acpi_ntfy(struct notifier_block *nb, unsigned long val, { struct nouveau_drm *drm = container_of(nb, typeof(*drm), acpi_nb); struct acpi_bus_event *info = data; + int ret; if (!strcmp(info->device_class, ACPI_VIDEO_CLASS)) { if (info->type == ACPI_VIDEO_NOTIFY_PROBE) { - /* - * This may be the only indication we receive of a - * connector hotplug on a runtime suspended GPU, - * schedule hpd_work to check. - */ - schedule_work(&drm->hpd_work); + ret = pm_runtime_get(drm->dev->dev); + if (ret == 1 || ret == -EACCES) { + /* If the GPU is already awake, or in a state + * where we can't wake it up, it can handle + * it's own hotplug events. + */ + pm_runtime_put_autosuspend(drm->dev->dev); + } else if (ret == 0) { + /* This may be the only indication we receive + * of a connector hotplug on a runtime + * suspended GPU, schedule hpd_work to check. + */ + NV_DEBUG(drm, "ACPI requested connector reprobe\n"); + schedule_work(&drm->hpd_work); + pm_runtime_put_noidle(drm->dev->dev); + } else { + NV_WARN(drm, "Dropped ACPI reprobe event due to RPM error: %d\n", + ret); + } /* acpi-video should not generate keypresses for this */ return NOTIFY_BAD; @@ -412,6 +424,11 @@ nouveau_display_init(struct drm_device *dev) if (ret) return ret; + /* enable connector detection and polling for connectors without HPD + * support + */ + drm_kms_helper_poll_enable(dev); + /* enable hotplug interrupts */ drm_connector_list_iter_begin(dev, &conn_iter); nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) { @@ -426,7 +443,7 @@ nouveau_display_init(struct drm_device *dev) } void -nouveau_display_fini(struct drm_device *dev, bool suspend) +nouveau_display_fini(struct drm_device *dev, bool suspend, bool runtime) { struct nouveau_display *disp = nouveau_display(dev); struct nouveau_drm *drm = nouveau_drm(dev); @@ -451,6 +468,9 @@ nouveau_display_fini(struct drm_device *dev, bool suspend) } drm_connector_list_iter_end(&conn_iter); + if (!runtime) + cancel_work_sync(&drm->hpd_work); + drm_kms_helper_poll_disable(dev); disp->fini(dev); } @@ -640,11 +660,11 @@ nouveau_display_suspend(struct drm_device *dev, bool runtime) } } - nouveau_display_fini(dev, true); + nouveau_display_fini(dev, true, runtime); return 0; } - nouveau_display_fini(dev, true); + nouveau_display_fini(dev, true, runtime); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_framebuffer *nouveau_fb; diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h index 34cd144681b9ba71a0e5fcc94a48ba8cdf4be517..5e7dae79c2ee3b763ae3c52965f3d7b8245a5c72 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.h +++ b/drivers/gpu/drm/nouveau/nouveau_display.h @@ -64,7 +64,7 @@ nouveau_display(struct drm_device *dev) int nouveau_display_create(struct drm_device *dev); void nouveau_display_destroy(struct drm_device *dev); int nouveau_display_init(struct drm_device *dev); -void nouveau_display_fini(struct drm_device *dev, bool suspend); +void nouveau_display_fini(struct drm_device *dev, bool suspend, bool runtime); int nouveau_display_suspend(struct drm_device *dev, bool runtime); void nouveau_display_resume(struct drm_device *dev, bool runtime); int nouveau_display_vblank_enable(struct drm_device *, unsigned int); diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 362a34cb435db7ad2b8dd5810c9dd25a0d5b744e..7d3c7bb0ebfa9985aeb7482948b41319a6dffaae 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -546,7 +546,7 @@ nouveau_drm_unload(struct drm_device *dev) nouveau_debugfs_fini(drm); if (dev->mode_config.num_crtc) - nouveau_display_fini(dev, false); + nouveau_display_fini(dev, false, false); nouveau_display_destroy(dev); nouveau_bios_takedown(dev); @@ -848,8 +848,10 @@ nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) get_task_comm(tmpname, current); snprintf(name, sizeof(name), "%s[%d]", tmpname, pid_nr(fpriv->pid)); - if (!(cli = kzalloc(sizeof(*cli), GFP_KERNEL))) - return ret; + if (!(cli = kzalloc(sizeof(*cli), GFP_KERNEL))) { + ret = -ENOMEM; + goto done; + } ret = nouveau_cli_init(drm, name, cli); if (ret) diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 2170534101cafda1e66ccdf0ee5262a62fdde7bf..60ffb70bb9089c08040c8a2fe918cb471d998fb9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -599,7 +599,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, struct nouveau_bo *nvbo; uint32_t data; - if (unlikely(r->bo_index > req->nr_buffers)) { + if (unlikely(r->bo_index >= req->nr_buffers)) { NV_PRINTK(err, cli, "reloc bo index invalid\n"); ret = -EINVAL; break; @@ -609,7 +609,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, if (b->presumed.valid) continue; - if (unlikely(r->reloc_bo_index > req->nr_buffers)) { + if (unlikely(r->reloc_bo_index >= req->nr_buffers)) { NV_PRINTK(err, cli, "reloc container bo index invalid\n"); ret = -EINVAL; break; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c index 189ed80e21ffbd428174e458bb946f2880c3da57..fa1ead337c237cbca4fd53f6a84440ad9785bd59 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c @@ -23,6 +23,10 @@ #ifdef CONFIG_NOUVEAU_PLATFORM_DRIVER #include "priv.h" +#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU) +#include +#endif + static int nvkm_device_tegra_power_up(struct nvkm_device_tegra *tdev) { @@ -105,6 +109,15 @@ nvkm_device_tegra_probe_iommu(struct nvkm_device_tegra *tdev) unsigned long pgsize_bitmap; int ret; +#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU) + if (dev->archdata.mapping) { + struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); + + arm_iommu_detach_device(dev); + arm_iommu_release_mapping(mapping); + } +#endif + if (!tdev->func->iommu_bit) return; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 7c5bed29ffef164224825a3f9e0eaac7aa786239..6160a6158cf26c9c33539fbd8cdc45e4e0ec63ff 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -412,14 +412,10 @@ nvkm_dp_train(struct nvkm_dp *dp, u32 dataKBps) } static void -nvkm_dp_release(struct nvkm_outp *outp, struct nvkm_ior *ior) +nvkm_dp_disable(struct nvkm_outp *outp, struct nvkm_ior *ior) { struct nvkm_dp *dp = nvkm_dp(outp); - /* Prevent link from being retrained if sink sends an IRQ. */ - atomic_set(&dp->lt.done, 0); - ior->dp.nr = 0; - /* Execute DisableLT script from DP Info Table. */ nvbios_init(&ior->disp->engine.subdev, dp->info.script[4], init.outp = &dp->outp.info; @@ -428,6 +424,16 @@ nvkm_dp_release(struct nvkm_outp *outp, struct nvkm_ior *ior) ); } +static void +nvkm_dp_release(struct nvkm_outp *outp) +{ + struct nvkm_dp *dp = nvkm_dp(outp); + + /* Prevent link from being retrained if sink sends an IRQ. */ + atomic_set(&dp->lt.done, 0); + dp->outp.ior->dp.nr = 0; +} + static int nvkm_dp_acquire(struct nvkm_outp *outp) { @@ -576,6 +582,7 @@ nvkm_dp_func = { .fini = nvkm_dp_fini, .acquire = nvkm_dp_acquire, .release = nvkm_dp_release, + .disable = nvkm_dp_disable, }; static int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 0c570dbd3021b45472a31a96afee19e88a4adea0..bc18a96bc61aee1aaadb1ba36da859e1a6b983e5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -436,11 +436,11 @@ nv50_disp_super_2_0(struct nv50_disp *disp, struct nvkm_head *head) nv50_disp_super_ied_off(head, ior, 2); /* If we're shutting down the OR's only active head, execute - * the output path's release function. + * the output path's disable function. */ if (ior->arm.head == (1 << head->id)) { - if ((outp = ior->arm.outp) && outp->func->release) - outp->func->release(outp, ior); + if ((outp = ior->arm.outp) && outp->func->disable) + outp->func->disable(outp, ior); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c index be9e7f8c3b2392fa96643f91391e606196ad7a67..bbba77ff93857e850aabab910eeb596bad06aa94 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c @@ -93,6 +93,8 @@ nvkm_outp_release(struct nvkm_outp *outp, u8 user) if (ior) { outp->acquired &= ~user; if (!outp->acquired) { + if (outp->func->release && outp->ior) + outp->func->release(outp); outp->ior->asy.outp = NULL; outp->ior = NULL; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index ea84d7d5741ad5a5e771483a225f6fea8a663223..97196f802924304b7ca83ef2127cdbdc8e24026d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -41,7 +41,8 @@ struct nvkm_outp_func { void (*init)(struct nvkm_outp *); void (*fini)(struct nvkm_outp *); int (*acquire)(struct nvkm_outp *); - void (*release)(struct nvkm_outp *, struct nvkm_ior *); + void (*release)(struct nvkm_outp *); + void (*disable)(struct nvkm_outp *, struct nvkm_ior *); }; #define OUTP_MSG(o,l,f,a...) do { \ diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm200.c index 1730371933df7a587a54e9b8444403d0f6ff317a..be0dd6074b57d74faf93c39a29b00f8bf97894c6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm200.c @@ -158,7 +158,8 @@ gm200_devinit_post(struct nvkm_devinit *base, bool post) } /* load and execute some other ucode image (bios therm?) */ - return pmu_load(init, 0x01, post, NULL, NULL); + pmu_load(init, 0x01, post, NULL, NULL); + return 0; } static const struct nvkm_devinit_func diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c b/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c index a188a3959f1ad33384fb266b967853a61bb4f973..6ad827b93ae19a5082ddec0e08dd627b568a2af0 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e8aa0.c @@ -823,7 +823,7 @@ static void s6e8aa0_read_mtp_id(struct s6e8aa0 *ctx) int ret, i; ret = s6e8aa0_dcs_read(ctx, 0xd1, id, ARRAY_SIZE(id)); - if (ret < ARRAY_SIZE(id) || id[0] == 0x00) { + if (ret < 0 || ret < ARRAY_SIZE(id) || id[0] == 0x00) { dev_err(ctx->dev, "read id failed\n"); ctx->error = -EIO; return; diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index ace59651892fb636400088e2ac9136a0917d45dd..8d3c8070ed86238206f208f22cb84a10d90922cf 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -241,7 +241,6 @@ static int sun4i_drv_add_endpoints(struct device *dev, remote = of_graph_get_remote_port_parent(ep); if (!remote) { DRM_DEBUG_DRIVER("Error retrieving the output node\n"); - of_node_put(remote); continue; } @@ -255,11 +254,13 @@ static int sun4i_drv_add_endpoints(struct device *dev, if (of_graph_parse_endpoint(ep, &endpoint)) { DRM_DEBUG_DRIVER("Couldn't parse endpoint\n"); + of_node_put(remote); continue; } if (!endpoint.id) { DRM_DEBUG_DRIVER("Endpoint is our panel... skipping\n"); + of_node_put(remote); continue; } } diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 0598b4c18c253bb9f10076174a0b6c2774a86e87..75b1c8c03ce95eff8e9f824c1a161a70ffced508 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -470,7 +470,7 @@ int tegra_drm_submit(struct tegra_drm_context *context, * unaligned offset is malformed and cause commands stream * corruption on the buffer address relocation. */ - if (offset & 3 || offset >= obj->gem.size) { + if (offset & 3 || offset > obj->gem.size) { err = -EINVAL; goto fail; } diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h index 2a75ab80527a954990c6ee2305883a97fa2ea41b..2c149b841cf1edcc4e86032a73753ffefad53d25 100644 --- a/drivers/gpu/drm/udl/udl_drv.h +++ b/drivers/gpu/drm/udl/udl_drv.h @@ -110,7 +110,7 @@ udl_fb_user_fb_create(struct drm_device *dev, struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd); -int udl_render_hline(struct drm_device *dev, int bpp, struct urb **urb_ptr, +int udl_render_hline(struct drm_device *dev, int log_bpp, struct urb **urb_ptr, const char *front, char **urb_buf_ptr, u32 byte_offset, u32 device_byte_offset, u32 byte_width, int *ident_ptr, int *sent_ptr); diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c index d5583190f3e44de77560d76c2d5a5a4cf7db62de..491f1892b50e7995de815f44909f9cca6ebd07cd 100644 --- a/drivers/gpu/drm/udl/udl_fb.c +++ b/drivers/gpu/drm/udl/udl_fb.c @@ -90,7 +90,10 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y, int bytes_identical = 0; struct urb *urb; int aligned_x; - int bpp = fb->base.format->cpp[0]; + int log_bpp; + + BUG_ON(!is_power_of_2(fb->base.format->cpp[0])); + log_bpp = __ffs(fb->base.format->cpp[0]); if (!fb->active_16) return 0; @@ -125,12 +128,12 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y, for (i = y; i < y + height ; i++) { const int line_offset = fb->base.pitches[0] * i; - const int byte_offset = line_offset + (x * bpp); - const int dev_byte_offset = (fb->base.width * bpp * i) + (x * bpp); - if (udl_render_hline(dev, bpp, &urb, + const int byte_offset = line_offset + (x << log_bpp); + const int dev_byte_offset = (fb->base.width * i + x) << log_bpp; + if (udl_render_hline(dev, log_bpp, &urb, (char *) fb->obj->vmapping, &cmd, byte_offset, dev_byte_offset, - width * bpp, + width << log_bpp, &bytes_identical, &bytes_sent)) goto error; } @@ -149,7 +152,7 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y, error: atomic_add(bytes_sent, &udl->bytes_sent); atomic_add(bytes_identical, &udl->bytes_identical); - atomic_add(width*height*bpp, &udl->bytes_rendered); + atomic_add((width * height) << log_bpp, &udl->bytes_rendered); end_cycles = get_cycles(); atomic_add(((unsigned int) ((end_cycles - start_cycles) >> 10)), /* Kcycles */ @@ -221,7 +224,7 @@ static int udl_fb_open(struct fb_info *info, int user) struct fb_deferred_io *fbdefio; - fbdefio = kmalloc(sizeof(struct fb_deferred_io), GFP_KERNEL); + fbdefio = kzalloc(sizeof(struct fb_deferred_io), GFP_KERNEL); if (fbdefio) { fbdefio->delay = DL_DEFIO_WRITE_DELAY; @@ -429,9 +432,11 @@ static void udl_fbdev_destroy(struct drm_device *dev, { drm_fb_helper_unregister_fbi(&ufbdev->helper); drm_fb_helper_fini(&ufbdev->helper); - drm_framebuffer_unregister_private(&ufbdev->ufb.base); - drm_framebuffer_cleanup(&ufbdev->ufb.base); - drm_gem_object_put_unlocked(&ufbdev->ufb.obj->base); + if (ufbdev->ufb.obj) { + drm_framebuffer_unregister_private(&ufbdev->ufb.base); + drm_framebuffer_cleanup(&ufbdev->ufb.base); + drm_gem_object_put_unlocked(&ufbdev->ufb.obj->base); + } } int udl_fbdev_init(struct drm_device *dev) diff --git a/drivers/gpu/drm/udl/udl_main.c b/drivers/gpu/drm/udl/udl_main.c index 0328b2c7b210a0331f8721e93c3b25124ad27daf..f8ea3c99b523234273f705a3884a383df0949ae1 100644 --- a/drivers/gpu/drm/udl/udl_main.c +++ b/drivers/gpu/drm/udl/udl_main.c @@ -169,18 +169,13 @@ static void udl_free_urb_list(struct drm_device *dev) struct list_head *node; struct urb_node *unode; struct urb *urb; - int ret; unsigned long flags; DRM_DEBUG("Waiting for completes and freeing all render urbs\n"); /* keep waiting and freeing, until we've got 'em all */ while (count--) { - - /* Getting interrupted means a leak, but ok at shutdown*/ - ret = down_interruptible(&udl->urbs.limit_sem); - if (ret) - break; + down(&udl->urbs.limit_sem); spin_lock_irqsave(&udl->urbs.lock, flags); @@ -204,17 +199,22 @@ 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; - int i = 0; struct urb *urb; struct urb_node *unode; char *buf; + size_t wanted_size = count * size; spin_lock_init(&udl->urbs.lock); +retry: udl->urbs.size = size; INIT_LIST_HEAD(&udl->urbs.list); - while (i < count) { + sema_init(&udl->urbs.limit_sem, 0); + udl->urbs.count = 0; + udl->urbs.available = 0; + + while (udl->urbs.count * size < wanted_size) { unode = kzalloc(sizeof(struct urb_node), GFP_KERNEL); if (!unode) break; @@ -230,11 +230,16 @@ static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size) } unode->urb = urb; - buf = usb_alloc_coherent(udl->udev, MAX_TRANSFER, GFP_KERNEL, + buf = usb_alloc_coherent(udl->udev, size, GFP_KERNEL, &urb->transfer_dma); if (!buf) { kfree(unode); usb_free_urb(urb); + if (size > PAGE_SIZE) { + size /= 2; + udl_free_urb_list(dev); + goto retry; + } break; } @@ -245,16 +250,14 @@ static int udl_alloc_urb_list(struct drm_device *dev, int count, size_t size) list_add_tail(&unode->entry, &udl->urbs.list); - i++; + up(&udl->urbs.limit_sem); + udl->urbs.count++; + udl->urbs.available++; } - sema_init(&udl->urbs.limit_sem, i); - udl->urbs.count = i; - udl->urbs.available = i; - - DRM_DEBUG("allocated %d %d byte urbs\n", i, (int) size); + DRM_DEBUG("allocated %d %d byte urbs\n", udl->urbs.count, (int) size); - return i; + return udl->urbs.count; } struct urb *udl_get_urb(struct drm_device *dev) diff --git a/drivers/gpu/drm/udl/udl_transfer.c b/drivers/gpu/drm/udl/udl_transfer.c index b992644c17e6b565b414351b1e262d4b61c9f38d..f3331d33547a1708fc7be2ee4eaeda676da3ff13 100644 --- a/drivers/gpu/drm/udl/udl_transfer.c +++ b/drivers/gpu/drm/udl/udl_transfer.c @@ -83,12 +83,12 @@ static inline u16 pixel32_to_be16(const uint32_t pixel) ((pixel >> 8) & 0xf800)); } -static inline u16 get_pixel_val16(const uint8_t *pixel, int bpp) +static inline u16 get_pixel_val16(const uint8_t *pixel, int log_bpp) { - u16 pixel_val16 = 0; - if (bpp == 2) + u16 pixel_val16; + if (log_bpp == 1) pixel_val16 = *(const uint16_t *)pixel; - else if (bpp == 4) + else pixel_val16 = pixel32_to_be16(*(const uint32_t *)pixel); return pixel_val16; } @@ -125,8 +125,9 @@ static void udl_compress_hline16( const u8 *const pixel_end, uint32_t *device_address_ptr, uint8_t **command_buffer_ptr, - const uint8_t *const cmd_buffer_end, int bpp) + const uint8_t *const cmd_buffer_end, int log_bpp) { + const int bpp = 1 << log_bpp; const u8 *pixel = *pixel_start_ptr; uint32_t dev_addr = *device_address_ptr; uint8_t *cmd = *command_buffer_ptr; @@ -153,12 +154,12 @@ static void udl_compress_hline16( raw_pixels_count_byte = cmd++; /* we'll know this later */ raw_pixel_start = pixel; - cmd_pixel_end = pixel + min3(MAX_CMD_PIXELS + 1UL, - (unsigned long)(pixel_end - pixel) / bpp, - (unsigned long)(cmd_buffer_end - 1 - cmd) / 2) * bpp; + cmd_pixel_end = pixel + (min3(MAX_CMD_PIXELS + 1UL, + (unsigned long)(pixel_end - pixel) >> log_bpp, + (unsigned long)(cmd_buffer_end - 1 - cmd) / 2) << log_bpp); prefetch_range((void *) pixel, cmd_pixel_end - pixel); - pixel_val16 = get_pixel_val16(pixel, bpp); + pixel_val16 = get_pixel_val16(pixel, log_bpp); while (pixel < cmd_pixel_end) { const u8 *const start = pixel; @@ -170,7 +171,7 @@ static void udl_compress_hline16( pixel += bpp; while (pixel < cmd_pixel_end) { - pixel_val16 = get_pixel_val16(pixel, bpp); + pixel_val16 = get_pixel_val16(pixel, log_bpp); if (pixel_val16 != repeating_pixel_val16) break; pixel += bpp; @@ -179,10 +180,10 @@ static void udl_compress_hline16( if (unlikely(pixel > start + bpp)) { /* go back and fill in raw pixel count */ *raw_pixels_count_byte = (((start - - raw_pixel_start) / bpp) + 1) & 0xFF; + raw_pixel_start) >> log_bpp) + 1) & 0xFF; /* immediately after raw data is repeat byte */ - *cmd++ = (((pixel - start) / bpp) - 1) & 0xFF; + *cmd++ = (((pixel - start) >> log_bpp) - 1) & 0xFF; /* Then start another raw pixel span */ raw_pixel_start = pixel; @@ -192,14 +193,14 @@ static void udl_compress_hline16( if (pixel > raw_pixel_start) { /* finalize last RAW span */ - *raw_pixels_count_byte = ((pixel-raw_pixel_start) / bpp) & 0xFF; + *raw_pixels_count_byte = ((pixel - raw_pixel_start) >> log_bpp) & 0xFF; } else { /* undo unused byte */ cmd--; } - *cmd_pixels_count_byte = ((pixel - cmd_pixel_start) / bpp) & 0xFF; - dev_addr += ((pixel - cmd_pixel_start) / bpp) * 2; + *cmd_pixels_count_byte = ((pixel - cmd_pixel_start) >> log_bpp) & 0xFF; + dev_addr += ((pixel - cmd_pixel_start) >> log_bpp) * 2; } if (cmd_buffer_end <= MIN_RLX_CMD_BYTES + cmd) { @@ -222,19 +223,19 @@ static void udl_compress_hline16( * (that we can only write to, slowly, and can never read), and (optionally) * our shadow copy that tracks what's been sent to that hardware buffer. */ -int udl_render_hline(struct drm_device *dev, int bpp, struct urb **urb_ptr, +int udl_render_hline(struct drm_device *dev, int log_bpp, struct urb **urb_ptr, const char *front, char **urb_buf_ptr, u32 byte_offset, u32 device_byte_offset, u32 byte_width, int *ident_ptr, int *sent_ptr) { const u8 *line_start, *line_end, *next_pixel; - u32 base16 = 0 + (device_byte_offset / bpp) * 2; + u32 base16 = 0 + (device_byte_offset >> log_bpp) * 2; struct urb *urb = *urb_ptr; u8 *cmd = *urb_buf_ptr; u8 *cmd_end = (u8 *) urb->transfer_buffer + urb->transfer_buffer_length; - BUG_ON(!(bpp == 2 || bpp == 4)); + BUG_ON(!(log_bpp == 1 || log_bpp == 2)); line_start = (u8 *) (front + byte_offset); next_pixel = line_start; @@ -244,7 +245,7 @@ int udl_render_hline(struct drm_device *dev, int bpp, struct urb **urb_ptr, udl_compress_hline16(&next_pixel, line_end, &base16, - (u8 **) &cmd, (u8 *) cmd_end, bpp); + (u8 **) &cmd, (u8 *) cmd_end, log_bpp); if (cmd >= cmd_end) { int len = cmd - (u8 *) urb->transfer_buffer; diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 17590cb2b80d952b4479dc14b00b26c6db7ae379..502c7eb708c25914f142095a7a0c5a2182ce2226 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -329,6 +329,9 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) vc4_state->y_scaling[0] = vc4_get_scaling_mode(vc4_state->src_h[0], vc4_state->crtc_h); + vc4_state->is_unity = (vc4_state->x_scaling[0] == VC4_SCALING_NONE && + vc4_state->y_scaling[0] == VC4_SCALING_NONE); + if (num_planes > 1) { vc4_state->is_yuv = true; @@ -344,24 +347,17 @@ static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) vc4_get_scaling_mode(vc4_state->src_h[1], vc4_state->crtc_h); - /* YUV conversion requires that scaling be enabled, - * even on a plane that's otherwise 1:1. Choose TPZ - * for simplicity. + /* YUV conversion requires that horizontal scaling be enabled, + * even on a plane that's otherwise 1:1. Looks like only PPF + * works in that case, so let's pick that one. */ - if (vc4_state->x_scaling[0] == VC4_SCALING_NONE) - vc4_state->x_scaling[0] = VC4_SCALING_TPZ; - if (vc4_state->y_scaling[0] == VC4_SCALING_NONE) - vc4_state->y_scaling[0] = VC4_SCALING_TPZ; + if (vc4_state->is_unity) + vc4_state->x_scaling[0] = VC4_SCALING_PPF; } else { vc4_state->x_scaling[1] = VC4_SCALING_NONE; vc4_state->y_scaling[1] = VC4_SCALING_NONE; } - vc4_state->is_unity = (vc4_state->x_scaling[0] == VC4_SCALING_NONE && - vc4_state->y_scaling[0] == VC4_SCALING_NONE && - vc4_state->x_scaling[1] == VC4_SCALING_NONE && - vc4_state->y_scaling[1] == VC4_SCALING_NONE); - /* No configuring scaling on the cursor plane, since it gets non-vblank-synced updates, and scaling requires requires LBM changes which have to be vblank-synced. @@ -639,7 +635,10 @@ static int vc4_plane_mode_set(struct drm_plane *plane, vc4_dlist_write(vc4_state, SCALER_CSC2_ITR_R_601_5); } - if (!vc4_state->is_unity) { + if (vc4_state->x_scaling[0] != VC4_SCALING_NONE || + vc4_state->x_scaling[1] != VC4_SCALING_NONE || + vc4_state->y_scaling[0] != VC4_SCALING_NONE || + vc4_state->y_scaling[1] != VC4_SCALING_NONE) { /* LBM Base Address. */ if (vc4_state->y_scaling[0] != VC4_SCALING_NONE || vc4_state->y_scaling[1] != VC4_SCALING_NONE) { diff --git a/drivers/gpu/host1x/job.c b/drivers/gpu/host1x/job.c index db509ab8874e58fd1f798da270fa8035ed4563d3..acd99783bbca1ca8fffc8e8ba5b6105e67cdc09e 100644 --- a/drivers/gpu/host1x/job.c +++ b/drivers/gpu/host1x/job.c @@ -686,7 +686,8 @@ void host1x_job_unpin(struct host1x_job *job) for (i = 0; i < job->num_unpins; i++) { struct host1x_job_unpin_data *unpin = &job->unpins[i]; - if (!IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL) && host->domain) { + if (!IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL) && + unpin->size && host->domain) { iommu_unmap(host->domain, job->addr_phys[i], unpin->size); free_iova(&host->iova, diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index 658fa2d3e40c260d051d4299bda4eddb0af5abeb..2c8411b8d050d6d758522a9866e1cd2d3dfebb7d 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -1401,6 +1401,8 @@ static int ipu_probe(struct platform_device *pdev) return -ENODEV; ipu->id = of_alias_get_id(np, "ipu"); + if (ipu->id < 0) + ipu->id = 0; if (of_device_is_compatible(np, "fsl,imx6qp-ipu") && IS_ENABLED(CONFIG_DRM)) { diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c index 24e12b87a0cbe387b24557a230a1ed1d05e150ca..2bc51d4d3f1e6adf923e01e69f4e3ec92ee186d2 100644 --- a/drivers/gpu/ipu-v3/ipu-csi.c +++ b/drivers/gpu/ipu-v3/ipu-csi.c @@ -316,13 +316,17 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code) /* * Fill a CSI bus config struct from mbus_config and mbus_framefmt. */ -static void fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg, +static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg, struct v4l2_mbus_config *mbus_cfg, struct v4l2_mbus_framefmt *mbus_fmt) { + int ret; + memset(csicfg, 0, sizeof(*csicfg)); - mbus_code_to_bus_cfg(csicfg, mbus_fmt->code); + ret = mbus_code_to_bus_cfg(csicfg, mbus_fmt->code); + if (ret < 0) + return ret; switch (mbus_cfg->type) { case V4L2_MBUS_PARALLEL: @@ -353,6 +357,8 @@ static void fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg, /* will never get here, keep compiler quiet */ break; } + + return 0; } int ipu_csi_init_interface(struct ipu_csi *csi, @@ -362,8 +368,11 @@ int ipu_csi_init_interface(struct ipu_csi *csi, struct ipu_csi_bus_config cfg; unsigned long flags; u32 width, height, data = 0; + int ret; - fill_csi_bus_cfg(&cfg, mbus_cfg, mbus_fmt); + ret = fill_csi_bus_cfg(&cfg, mbus_cfg, mbus_fmt); + if (ret < 0) + return ret; /* set default sensor frame width and height */ width = mbus_fmt->width; @@ -584,11 +593,14 @@ int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc, struct ipu_csi_bus_config cfg; unsigned long flags; u32 temp; + int ret; if (vc > 3) return -EINVAL; - mbus_code_to_bus_cfg(&cfg, mbus_fmt->code); + ret = mbus_code_to_bus_cfg(&cfg, mbus_fmt->code); + if (ret < 0) + return ret; spin_lock_irqsave(&csi->lock, flags); diff --git a/drivers/gpu/msm/a6xx_reg.h b/drivers/gpu/msm/a6xx_reg.h index 9c1e798367b23ada33045134b420611a2853d5f5..17fa6d11e969c00234c99e20e97bd6e9f181a44e 100644 --- a/drivers/gpu/msm/a6xx_reg.h +++ b/drivers/gpu/msm/a6xx_reg.h @@ -58,9 +58,11 @@ #define A6XX_CP_RB_RPTR 0x806 #define A6XX_CP_RB_WPTR 0x807 #define A6XX_CP_SQE_CNTL 0x808 +#define A6XX_CP_CP2GMU_STATUS 0x812 #define A6XX_CP_HW_FAULT 0x821 #define A6XX_CP_INTERRUPT_STATUS 0x823 -#define A6XX_CP_PROTECT_STATUS 0X824 +#define A6XX_CP_PROTECT_STATUS 0x824 +#define A6XX_CP_STATUS_1 0x825 #define A6XX_CP_SQE_INSTR_BASE_LO 0x830 #define A6XX_CP_SQE_INSTR_BASE_HI 0x831 #define A6XX_CP_MISC_CNTL 0x840 @@ -1111,5 +1113,16 @@ #define A6XX_RGMU_CX_PCC_STATUS 0x1F83C #define A6XX_RGMU_CX_PCC_DEBUG 0x1F83D +/* GPU CX_MISC registers */ +#define A6XX_GPU_CX_MISC_SYSTEM_CACHE_CNTL_0 0x1 +#define A6XX_GPU_CX_MISC_SYSTEM_CACHE_CNTL_1 0x2 +#define A6XX_LLC_NUM_GPU_SCIDS 5 +#define A6XX_GPU_LLC_SCID_NUM_BITS 5 +#define A6XX_GPU_LLC_SCID_MASK \ + ((1 << (A6XX_LLC_NUM_GPU_SCIDS * A6XX_GPU_LLC_SCID_NUM_BITS)) - 1) +#define A6XX_GPUHTW_LLC_SCID_SHIFT 25 +#define A6XX_GPUHTW_LLC_SCID_MASK \ + (((1 << A6XX_GPU_LLC_SCID_NUM_BITS) - 1) << A6XX_GPUHTW_LLC_SCID_SHIFT) + #endif /* _A6XX_REG_H */ diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h index 5ac715d93093ce5ad3640f0ba4052bd7283f9144..efc240f3b64724149d30ff19dce79088571826d5 100644 --- a/drivers/gpu/msm/adreno-gpulist.h +++ b/drivers/gpu/msm/adreno-gpulist.h @@ -380,6 +380,25 @@ static const struct adreno_gpu_core adreno_gpulist[] = { .gpmu_major = 0x1, .gpmu_minor = 0x003, }, + { + .gpurev = ADRENO_REV_A618, + .core = 6, + .major = 1, + .minor = 8, + .patchid = ANY_ID, + .features = ADRENO_64BIT | ADRENO_RPMH | ADRENO_PREEMPTION | + ADRENO_GPMU | ADRENO_CONTENT_PROTECTION | ADRENO_IFPC | + ADRENO_IOCOHERENT, + .sqefw_name = "a630_sqe.fw", + .zap_name = "a615_zap", + .gpudev = &adreno_a6xx_gpudev, + .gmem_size = SZ_512K, + .num_protected_regs = 0x20, + .busy_mask = 0xFFFFFFFE, + .gpmufw_name = "a630_gmu.bin", + .gpmu_major = 0x1, + .gpmu_minor = 0x003, + }, { .gpurev = ADRENO_REV_A640, .core = 6, @@ -449,7 +468,8 @@ static const struct adreno_gpu_core adreno_gpulist[] = { .minor = 8, .patchid = ANY_ID, .features = ADRENO_64BIT | ADRENO_CONTENT_PROTECTION | - ADRENO_IOCOHERENT | ADRENO_PREEMPTION | ADRENO_GPMU, + ADRENO_IOCOHERENT | ADRENO_PREEMPTION | ADRENO_GPMU | + ADRENO_IFPC, .sqefw_name = "a630_sqe.fw", .zap_name = "a608_zap", .gpudev = &adreno_a6xx_gpudev, @@ -457,6 +477,7 @@ static const struct adreno_gpu_core adreno_gpulist[] = { .num_protected_regs = 0x20, .busy_mask = 0xFFFFFFFE, .gpmufw_name = "a608_rgmu.bin", + .cx_ipeak_gpu_freq = 745000000, }, { .gpurev = ADRENO_REV_A616, diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index f7bfae825a4de6de83b010836456dcb942046518..bed32d8f1cf2a24026ec25941aca624bb372a7bf 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -966,10 +966,6 @@ static int adreno_of_parse_pwrlevels(struct adreno_device *adreno_dev, if (of_property_read_u32(child, "qcom,bus-max", &level->bus_max)) level->bus_max = level->bus_freq; - - if (of_property_read_u32(child, "qcom,dvm-val", - &level->acd_dvm_val)) - level->acd_dvm_val = 0xFFFFFFFF; } return 0; @@ -1092,6 +1088,7 @@ static int adreno_of_get_power(struct adreno_device *adreno_dev, struct device_node *node = pdev->dev.of_node; struct resource *res; unsigned int timeout; + unsigned int throt = 4; if (of_property_read_string(node, "label", &pdev->name)) { KGSL_CORE_ERR("Unable to read 'label'\n"); @@ -1120,6 +1117,14 @@ static int adreno_of_get_power(struct adreno_device *adreno_dev, if (adreno_of_get_pwrlevels(adreno_dev, node)) return -EINVAL; + /* Get throttle power level */ + of_property_read_u32(node, "qcom,throttle-pwrlevel", &throt); + + if (throt < device->pwrctrl.num_pwrlevels) + device->pwrctrl.throttle_mask = + GENMASK(device->pwrctrl.num_pwrlevels - 1, + device->pwrctrl.num_pwrlevels - 1 - throt); + /* Get context aware DCVS properties */ adreno_of_get_ca_aware_properties(adreno_dev, node); @@ -1219,6 +1224,22 @@ static void adreno_cx_dbgc_probe(struct kgsl_device *device) KGSL_DRV_WARN(device, "cx_dbgc ioremap failed\n"); } +static void adreno_cx_misc_probe(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct resource *res; + + res = platform_get_resource_byname(device->pdev, IORESOURCE_MEM, + "cx_misc"); + + if (res == NULL) + return; + + adreno_dev->cx_misc_len = resource_size(res); + adreno_dev->cx_misc_virt = devm_ioremap(device->dev, + res->start, adreno_dev->cx_misc_len); +} + static void adreno_efuse_read_soc_hw_rev(struct adreno_device *adreno_dev) { unsigned int val; @@ -1351,6 +1372,9 @@ static int adreno_probe(struct platform_device *pdev) /* Probe for the optional CX_DBGC block */ adreno_cx_dbgc_probe(device); + /* Probe for the optional CX_MISC block */ + adreno_cx_misc_probe(device); + /* * qcom,iommu-secure-id is used to identify MMUs that can handle secure * content but that is only part of the story - the GPU also has to be @@ -1863,7 +1887,7 @@ static int _adreno_start(struct adreno_device *adreno_dev) status = kgsl_mmu_start(device); if (status) - goto error_pwr_off; + goto error_boot_oob_clear; status = adreno_ocmem_malloc(adreno_dev); if (status) { @@ -2087,6 +2111,11 @@ static int _adreno_start(struct adreno_device *adreno_dev) error_mmu_off: kgsl_mmu_stop(&device->mmu); +error_boot_oob_clear: + if (GMU_DEV_OP_VALID(gmu_dev_ops, oob_clear) && + ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) + gmu_dev_ops->oob_clear(adreno_dev, oob_boot_slumber); + error_pwr_off: /* set the state back to original state */ kgsl_pwrctrl_change_state(device, state); @@ -3370,6 +3399,54 @@ void adreno_cx_dbgc_regwrite(struct kgsl_device *device, __raw_writel(value, adreno_dev->cx_dbgc_virt + cx_dbgc_offset); } +void adreno_cx_misc_regread(struct adreno_device *adreno_dev, + unsigned int offsetwords, unsigned int *value) +{ + unsigned int cx_misc_offset; + + cx_misc_offset = (offsetwords << 2); + if (!adreno_dev->cx_misc_virt || + (cx_misc_offset >= adreno_dev->cx_misc_len)) + return; + + *value = __raw_readl(adreno_dev->cx_misc_virt + cx_misc_offset); + + /* + * ensure this read finishes before the next one. + * i.e. act like normal readl() + */ + rmb(); +} + +void adreno_cx_misc_regwrite(struct adreno_device *adreno_dev, + unsigned int offsetwords, unsigned int value) +{ + unsigned int cx_misc_offset; + + cx_misc_offset = (offsetwords << 2); + if (!adreno_dev->cx_misc_virt || + (cx_misc_offset >= adreno_dev->cx_misc_len)) + return; + + /* + * ensure previous writes post before this one, + * i.e. act like normal writel() + */ + wmb(); + __raw_writel(value, adreno_dev->cx_misc_virt + cx_misc_offset); +} + +void adreno_cx_misc_regrmw(struct adreno_device *adreno_dev, + unsigned int offsetwords, + unsigned int mask, unsigned int bits) +{ + unsigned int val = 0; + + adreno_cx_misc_regread(adreno_dev, offsetwords, &val); + val &= ~mask; + adreno_cx_misc_regwrite(adreno_dev, offsetwords, val | bits); +} + /** * adreno_waittimestamp - sleep while waiting for the specified timestamp * @device - pointer to a KGSL device structure diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 4cca2019fc87508c5e9e7c5587828bfe95dc6429..ac2447ccee07e3192228da54ce2cd05e378f84d2 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -220,6 +220,7 @@ enum adreno_gpurev { ADRENO_REV_A608 = 608, ADRENO_REV_A615 = 615, ADRENO_REV_A616 = 616, + ADRENO_REV_A618 = 618, ADRENO_REV_A630 = 630, ADRENO_REV_A640 = 640, ADRENO_REV_A680 = 680, @@ -440,6 +441,8 @@ enum gpu_coresight_sources { * @chipid: Chip ID specific to the GPU * @gmem_base: Base physical address of GMEM * @gmem_size: GMEM size + * @cx_misc_len: Length of the CX MISC register block + * @cx_misc_virt: Pointer where the CX MISC block is mapped * @gpucore: Pointer to the adreno_gpu_core structure * @pfp_fw: Buffer which holds the pfp ucode * @pfp_fw_size: Size of pfp ucode buffer @@ -520,6 +523,8 @@ struct adreno_device { unsigned long cx_dbgc_base; unsigned int cx_dbgc_len; void __iomem *cx_dbgc_virt; + unsigned int cx_misc_len; + void __iomem *cx_misc_virt; const struct adreno_gpu_core *gpucore; struct adreno_firmware fw[2]; size_t gpmu_cmds_size; @@ -1168,6 +1173,14 @@ void adreno_cx_dbgc_regread(struct kgsl_device *adreno_device, unsigned int offsetwords, unsigned int *value); void adreno_cx_dbgc_regwrite(struct kgsl_device *device, unsigned int offsetwords, unsigned int value); +void adreno_cx_misc_regread(struct adreno_device *adreno_dev, + unsigned int offsetwords, unsigned int *value); +void adreno_cx_misc_regwrite(struct adreno_device *adreno_dev, + unsigned int offsetwords, unsigned int value); +void adreno_cx_misc_regrmw(struct adreno_device *adreno_dev, + unsigned int offsetwords, + unsigned int mask, unsigned int bits); + #define ADRENO_TARGET(_name, _id) \ static inline int adreno_is_##_name(struct adreno_device *adreno_dev) \ @@ -1284,12 +1297,23 @@ static inline int adreno_is_a6xx(struct adreno_device *adreno_dev) } ADRENO_TARGET(a608, ADRENO_REV_A608) -ADRENO_TARGET(a615, ADRENO_REV_A615) -ADRENO_TARGET(a616, ADRENO_REV_A616) +ADRENO_TARGET(a618, ADRENO_REV_A618) ADRENO_TARGET(a630, ADRENO_REV_A630) ADRENO_TARGET(a640, ADRENO_REV_A640) ADRENO_TARGET(a680, ADRENO_REV_A680) +/* + * All the derived chipsets from A615 needs to be added to this + * list such as A616, A618 etc. + */ +static inline int adreno_is_a615_family(struct adreno_device *adreno_dev) +{ + unsigned int rev = ADRENO_GPUREV(adreno_dev); + + return (rev == ADRENO_REV_A615 || rev == ADRENO_REV_A616 || + rev == ADRENO_REV_A618); +} + static inline int adreno_is_a630v1(struct adreno_device *adreno_dev) { return (ADRENO_GPUREV(adreno_dev) == ADRENO_REV_A630) && @@ -1930,8 +1954,7 @@ static inline void adreno_perfcntr_active_oob_put( static inline bool adreno_has_sptprac_gdsc(struct adreno_device *adreno_dev) { - if (adreno_is_a615(adreno_dev) || adreno_is_a630(adreno_dev) || - adreno_is_a616(adreno_dev)) + if (adreno_is_a630(adreno_dev) || adreno_is_a615_family(adreno_dev)) return true; else return false; diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 74166cfab0d370594fb14618e3a62e252be1f1f9..2443316fe46476b4084fe849eaf78d5e689520e1 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -32,18 +32,6 @@ #define MIN_HBB 13 -#define A6XX_LLC_NUM_GPU_SCIDS 5 -#define A6XX_GPU_LLC_SCID_NUM_BITS 5 -#define A6XX_GPU_LLC_SCID_MASK \ - ((1 << (A6XX_LLC_NUM_GPU_SCIDS * A6XX_GPU_LLC_SCID_NUM_BITS)) - 1) -#define A6XX_GPUHTW_LLC_SCID_SHIFT 25 -#define A6XX_GPUHTW_LLC_SCID_MASK \ - (((1 << A6XX_GPU_LLC_SCID_NUM_BITS) - 1) << A6XX_GPUHTW_LLC_SCID_SHIFT) - -#define A6XX_GPU_CX_REG_BASE 0x509E000 -#define A6XX_GPU_CX_REG_SIZE 0x1000 - - static const struct adreno_vbif_data a630_vbif[] = { {A6XX_VBIF_GATE_OFF_WRREQ_EN, 0x00000009}, {A6XX_RBBM_VBIF_CLIENT_QOS_CNTL, 0x3}, @@ -66,11 +54,10 @@ static const struct adreno_vbif_data a640_gbif[] = { static const struct adreno_vbif_platform a6xx_vbif_platforms[] = { { adreno_is_a630, a630_vbif }, - { adreno_is_a615, a615_gbif }, + { adreno_is_a615_family, a615_gbif }, { adreno_is_a640, a640_gbif }, { adreno_is_a680, a640_gbif }, { adreno_is_a608, a615_gbif }, - { adreno_is_a616, a615_gbif }, }; struct kgsl_hwcg_reg { @@ -361,11 +348,10 @@ static const struct { unsigned int count; } a6xx_hwcg_registers[] = { {adreno_is_a630, a630_hwcg_regs, ARRAY_SIZE(a630_hwcg_regs)}, - {adreno_is_a615, a615_hwcg_regs, ARRAY_SIZE(a615_hwcg_regs)}, + {adreno_is_a615_family, a615_hwcg_regs, ARRAY_SIZE(a615_hwcg_regs)}, {adreno_is_a640, a640_hwcg_regs, ARRAY_SIZE(a640_hwcg_regs)}, {adreno_is_a680, a640_hwcg_regs, ARRAY_SIZE(a640_hwcg_regs)}, {adreno_is_a608, a608_hwcg_regs, ARRAY_SIZE(a608_hwcg_regs)}, - {adreno_is_a616, a615_hwcg_regs, ARRAY_SIZE(a615_hwcg_regs)}, }; static struct a6xx_protected_regs { @@ -612,7 +598,7 @@ __get_gmu_ao_cgc_mode_cntl(struct adreno_device *adreno_dev) { if (adreno_is_a608(adreno_dev)) return 0x00000022; - if (adreno_is_a615(adreno_dev) || adreno_is_a616(adreno_dev)) + else if (adreno_is_a615_family(adreno_dev)) return 0x00000222; else return 0x00020202; @@ -623,7 +609,7 @@ __get_gmu_ao_cgc_delay_cntl(struct adreno_device *adreno_dev) { if (adreno_is_a608(adreno_dev)) return 0x00000011; - if (adreno_is_a615(adreno_dev) || adreno_is_a616(adreno_dev)) + else if (adreno_is_a615_family(adreno_dev)) return 0x00000111; else return 0x00010111; @@ -634,7 +620,7 @@ __get_gmu_ao_cgc_hyst_cntl(struct adreno_device *adreno_dev) { if (adreno_is_a608(adreno_dev)) return 0x00000055; - if (adreno_is_a615(adreno_dev) || adreno_is_a616(adreno_dev)) + else if (adreno_is_a615_family(adreno_dev)) return 0x00000555; else return 0x00005555; @@ -748,8 +734,7 @@ static void a6xx_patch_pwrup_reglist(struct adreno_device *adreno_dev) + sizeof(a6xx_ifpc_pwrup_reglist), a6xx_pwrup_reglist, sizeof(a6xx_pwrup_reglist)); - if (adreno_is_a615(adreno_dev) || adreno_is_a608(adreno_dev) || - adreno_is_a616(adreno_dev)) { + if (adreno_is_a615_family(adreno_dev) || adreno_is_a608(adreno_dev)) { for (i = 0; i < ARRAY_SIZE(a615_pwrup_reglist); i++) { r = &a615_pwrup_reglist[i]; kgsl_regread(KGSL_DEVICE(adreno_dev), @@ -761,7 +746,7 @@ static void a6xx_patch_pwrup_reglist(struct adreno_device *adreno_dev) + sizeof(a6xx_pwrup_reglist), a615_pwrup_reglist, sizeof(a615_pwrup_reglist)); - lock->list_length += sizeof(a615_pwrup_reglist); + lock->list_length += sizeof(a615_pwrup_reglist) >> 2; } } @@ -1427,7 +1412,7 @@ static int a6xx_soft_reset(struct adreno_device *adreno_dev) static int64_t a6xx_read_throttling_counters(struct adreno_device *adreno_dev) { int i; - int64_t adj = 0; + int64_t adj = -1; uint32_t counts[ADRENO_GPMU_THROTTLE_COUNTERS]; struct adreno_busy_data *busy = &adreno_dev->busy_data; @@ -1443,12 +1428,12 @@ static int64_t a6xx_read_throttling_counters(struct adreno_device *adreno_dev) /* * The adjustment is the number of cycles lost to throttling, which * is calculated as a weighted average of the cycles throttled - * at 10%, 50%, and 90%. The adjustment is negative because in A6XX, + * at 15%, 50%, and 90%. The adjustment is negative because in A6XX, * the busy count includes the throttled cycles. Therefore, we want * to remove them to prevent appearing to be busier than * we actually are. */ - adj = -((counts[0] * 1) + (counts[1] * 5) + (counts[2] * 9)) / 10; + adj *= ((counts[0] * 15) + (counts[1] * 50) + (counts[2] * 90)) / 100; trace_kgsl_clock_throttling(0, counts[1], counts[2], counts[0], adj); @@ -1597,24 +1582,6 @@ static void a6xx_err_callback(struct adreno_device *adreno_dev, int bit) } } -/* GPU System Cache control registers */ -#define A6XX_GPU_CX_MISC_SYSTEM_CACHE_CNTL_0 0x4 -#define A6XX_GPU_CX_MISC_SYSTEM_CACHE_CNTL_1 0x8 - -static inline void _reg_rmw(void __iomem *regaddr, - unsigned int mask, unsigned int bits) -{ - unsigned int val = 0; - - val = __raw_readl(regaddr); - /* Make sure the above read completes before we proceed */ - rmb(); - val &= ~mask; - __raw_writel(val | bits, regaddr); - /* Make sure the above write posts before we proceed*/ - wmb(); -} - /* * a6xx_llc_configure_gpu_scid() - Program the sub-cache ID for all GPU blocks * @adreno_dev: The adreno device pointer @@ -1630,17 +1597,13 @@ static void a6xx_llc_configure_gpu_scid(struct adreno_device *adreno_dev) gpu_cntl1_val = (gpu_cntl1_val << A6XX_GPU_LLC_SCID_NUM_BITS) | gpu_scid; - if (adreno_is_a640(adreno_dev)) { + if (adreno_is_a640(adreno_dev) || adreno_is_a608(adreno_dev)) { kgsl_regrmw(KGSL_DEVICE(adreno_dev), A6XX_GBIF_SCACHE_CNTL1, A6XX_GPU_LLC_SCID_MASK, gpu_cntl1_val); } else { - void __iomem *gpu_cx_reg; - - gpu_cx_reg = ioremap(A6XX_GPU_CX_REG_BASE, - A6XX_GPU_CX_REG_SIZE); - _reg_rmw(gpu_cx_reg + A6XX_GPU_CX_MISC_SYSTEM_CACHE_CNTL_1, - A6XX_GPU_LLC_SCID_MASK, gpu_cntl1_val); - iounmap(gpu_cx_reg); + adreno_cx_misc_regrmw(adreno_dev, + A6XX_GPU_CX_MISC_SYSTEM_CACHE_CNTL_1, + A6XX_GPU_LLC_SCID_MASK, gpu_cntl1_val); } } @@ -1651,22 +1614,20 @@ static void a6xx_llc_configure_gpu_scid(struct adreno_device *adreno_dev) static void a6xx_llc_configure_gpuhtw_scid(struct adreno_device *adreno_dev) { uint32_t gpuhtw_scid; - void __iomem *gpu_cx_reg; /* * On A640, the GPUHTW SCID is configured via a NoC override in the * XBL image. */ - if (adreno_is_a640(adreno_dev)) + if (adreno_is_a640(adreno_dev) || adreno_is_a608(adreno_dev)) return; gpuhtw_scid = adreno_llc_get_scid(adreno_dev->gpuhtw_llc_slice); - gpu_cx_reg = ioremap(A6XX_GPU_CX_REG_BASE, A6XX_GPU_CX_REG_SIZE); - _reg_rmw(gpu_cx_reg + A6XX_GPU_CX_MISC_SYSTEM_CACHE_CNTL_1, + adreno_cx_misc_regrmw(adreno_dev, + A6XX_GPU_CX_MISC_SYSTEM_CACHE_CNTL_1, A6XX_GPUHTW_LLC_SCID_MASK, gpuhtw_scid << A6XX_GPUHTW_LLC_SCID_SHIFT); - iounmap(gpu_cx_reg); } /* @@ -1675,13 +1636,11 @@ static void a6xx_llc_configure_gpuhtw_scid(struct adreno_device *adreno_dev) */ static void a6xx_llc_enable_overrides(struct adreno_device *adreno_dev) { - void __iomem *gpu_cx_reg; - /* * Attributes override through GBIF is not supported with MMU-500. * Attributes are used as configured through SMMU pagetable entries. */ - if (adreno_is_a640(adreno_dev)) + if (adreno_is_a640(adreno_dev) || adreno_is_a608(adreno_dev)) return; /* @@ -1690,11 +1649,8 @@ static void a6xx_llc_enable_overrides(struct adreno_device *adreno_dev) * writenoallocoverrideen=1 * write-no-alloc=1 - Do not allocates lines on write miss */ - gpu_cx_reg = ioremap(A6XX_GPU_CX_REG_BASE, A6XX_GPU_CX_REG_SIZE); - __raw_writel(0x3, gpu_cx_reg + A6XX_GPU_CX_MISC_SYSTEM_CACHE_CNTL_0); - /* Make sure the above write posts before we proceed*/ - wmb(); - iounmap(gpu_cx_reg); + adreno_cx_misc_regwrite(adreno_dev, + A6XX_GPU_CX_MISC_SYSTEM_CACHE_CNTL_0, 0x3); } static const char *fault_block[8] = { @@ -2703,9 +2659,8 @@ static const struct { int (*check)(struct adreno_device *adreno_dev); void (*func)(struct adreno_device *adreno_dev); } a6xx_efuse_funcs[] = { - { adreno_is_a615, a6xx_efuse_speed_bin }, + { adreno_is_a615_family, a6xx_efuse_speed_bin }, { adreno_is_a608, a6xx_efuse_speed_bin }, - { adreno_is_a616, a6xx_efuse_speed_bin }, }; static void a6xx_check_features(struct adreno_device *adreno_dev) diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index ca1622d80bdca545d22c8c2342dc0041299c1f27..7f32df04effddff149c48158d95f9524953c1158 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -194,7 +194,8 @@ static int _load_gmu_rpmh_ucode(struct kgsl_device *device) _regwrite(cfg, PDC_GPU_TCS1_CMD0_DATA + PDC_CMD_OFFSET, 0x0); _regwrite(cfg, PDC_GPU_TCS1_CMD0_MSGID + PDC_CMD_OFFSET * 2, 0x10108); - if (adreno_is_a640(adreno_dev) || adreno_is_a680(adreno_dev)) + if (adreno_is_a640(adreno_dev) || adreno_is_a680(adreno_dev) || + adreno_is_a618(adreno_dev)) _regwrite(cfg, PDC_GPU_TCS1_CMD0_ADDR + PDC_CMD_OFFSET * 2, 0x30090); else @@ -213,7 +214,8 @@ static int _load_gmu_rpmh_ucode(struct kgsl_device *device) _regwrite(cfg, PDC_GPU_TCS3_CMD0_DATA + PDC_CMD_OFFSET, 0x3); _regwrite(cfg, PDC_GPU_TCS3_CMD0_MSGID + PDC_CMD_OFFSET * 2, 0x10108); - if (adreno_is_a640(adreno_dev) || adreno_is_a680(adreno_dev)) + if (adreno_is_a640(adreno_dev) || adreno_is_a680(adreno_dev) || + adreno_is_a618(adreno_dev)) _regwrite(cfg, PDC_GPU_TCS3_CMD0_ADDR + PDC_CMD_OFFSET * 2, 0x30090); else @@ -459,6 +461,25 @@ static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device) return 0; } +static int _load_legacy_gmu_fw(struct kgsl_device *device, + struct gmu_device *gmu) +{ + const struct firmware *fw = gmu->fw_image; + u32 *fwptr = (u32 *)fw->data; + int i; + + if (fw->size > MAX_GMUFW_SIZE) + return -EINVAL; + + for (i = 0; i < (fw->size >> 2); i++) + gmu_core_regwrite(device, + A6XX_GMU_CM3_ITCM_START + i, fwptr[i]); + + /* Proceed only after the FW is written */ + wmb(); + return 0; +} + static int load_gmu_fw(struct kgsl_device *device) { struct gmu_device *gmu = KGSL_GMU_DEVICE(device); @@ -468,6 +489,10 @@ static int load_gmu_fw(struct kgsl_device *device) struct gmu_block_header *blk; struct gmu_memdesc *md; + if (adreno_is_a630(ADRENO_DEVICE(device)) || + adreno_is_a615_family(ADRENO_DEVICE(device))) + return _load_legacy_gmu_fw(device, gmu); + while (fw < (uint8_t *)gmu->fw_image->data + gmu->fw_image->size) { blk = (struct gmu_block_header *)fw; fw += sizeof(*blk); @@ -529,8 +554,7 @@ static int a6xx_gmu_oob_set(struct adreno_device *adreno_dev, if (!gmu_core_isenabled(device)) return 0; - if (!adreno_is_a630(adreno_dev) && !adreno_is_a615(adreno_dev) && - !adreno_is_a616(adreno_dev)) { + if (!adreno_is_a630(adreno_dev) && !adreno_is_a615_family(adreno_dev)) { set = BIT(30 - req * 2); check = BIT(31 - req); @@ -583,8 +607,7 @@ static inline void a6xx_gmu_oob_clear(struct adreno_device *adreno_dev, if (!gmu_core_isenabled(device)) return; - if (!adreno_is_a630(adreno_dev) && !adreno_is_a615(adreno_dev) && - !adreno_is_a616(adreno_dev)) { + if (!adreno_is_a630(adreno_dev) && !adreno_is_a615_family(adreno_dev)) { clear = BIT(31 - req * 2); if (req >= 6) { dev_err(&gmu->pdev->dev, @@ -815,7 +838,7 @@ static int a6xx_gmu_gfx_rail_on(struct kgsl_device *device) return a6xx_gmu_oob_set(adreno_dev, oob_boot_slumber); } -static bool idle_trandition_complete(unsigned int idle_level, +static bool idle_transition_complete(unsigned int idle_level, unsigned int gmu_power_reg, unsigned int sptprac_clk_reg) { @@ -839,7 +862,7 @@ static int a6xx_gmu_wait_for_lowest_idle(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct gmu_device *gmu = KGSL_GMU_DEVICE(device); - unsigned int reg, reg1; + unsigned int reg, reg1, reg2, reg3, reg4, reg5, reg6, reg7, reg8; unsigned long t; uint64_t ts1, ts2, ts3; @@ -855,7 +878,7 @@ static int a6xx_gmu_wait_for_lowest_idle(struct adreno_device *adreno_dev) gmu_core_regread(device, A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, ®1); - if (idle_trandition_complete(gmu->idle_level, reg, reg1)) + if (idle_transition_complete(gmu->idle_level, reg, reg1)) return 0; /* Wait 100us to reduce unnecessary AHB bus traffic */ usleep_range(10, 100); @@ -867,13 +890,38 @@ static int a6xx_gmu_wait_for_lowest_idle(struct adreno_device *adreno_dev) gmu_core_regread(device, A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE, ®); gmu_core_regread(device, A6XX_GMU_SPTPRAC_PWR_CLK_STATUS, ®1); - if (idle_trandition_complete(gmu->idle_level, reg, reg1)) + if (idle_transition_complete(gmu->idle_level, reg, reg1)) return 0; ts3 = read_AO_counter(device); - WARN(1, "Timeout waiting for lowest idle: %08x %llx %llx %llx %x\n", - reg, ts1, ts2, ts3, reg1); + /* Collect abort data to help with debugging */ + gmu_core_regread(device, A6XX_GPU_GMU_AO_GPU_CX_BUSY_STATUS, ®2); + gmu_core_regread(device, A6XX_CP_STATUS_1, ®3); + gmu_core_regread(device, A6XX_GMU_RBBM_INT_UNMASKED_STATUS, ®4); + gmu_core_regread(device, A6XX_GMU_GMU_PWR_COL_KEEPALIVE, ®5); + gmu_core_regread(device, A6XX_CP_CP2GMU_STATUS, ®6); + gmu_core_regread(device, A6XX_CP_CONTEXT_SWITCH_CNTL, ®7); + gmu_core_regread(device, A6XX_GMU_AO_SPARE_CNTL, ®8); + + dev_err(&gmu->pdev->dev, + "----------------------[ GMU error ]----------------------\n"); + dev_err(&gmu->pdev->dev, + "Timeout waiting for lowest idle level %d\n", gmu->idle_level); + dev_err(&gmu->pdev->dev, + "Timestamps: %llx %llx %llx\n", ts1, ts2, ts3); + dev_err(&gmu->pdev->dev, + "RPMH_POWER_STATE=%x SPTPRAC_PWR_CLK_STATUS=%x\n", reg, reg1); + dev_err(&gmu->pdev->dev, + "CX_BUSY_STATUS=%x CP_STATUS_1=%x\n", reg2, reg3); + dev_err(&gmu->pdev->dev, + "RBBM_INT_UNMASKED_STATUS=%x PWR_COL_KEEPALIVE=%x\n", + reg4, reg5); + dev_err(&gmu->pdev->dev, + "CP2GMU_STATUS=%x CONTEXT_SWITCH_CNTL=%x AO_SPARE_CNTL=%x\n", + reg6, reg7, reg8); + + WARN_ON(1); return -ETIMEDOUT; } diff --git a/drivers/gpu/msm/adreno_a6xx_snapshot.c b/drivers/gpu/msm/adreno_a6xx_snapshot.c index 42c7d742c22b4316cc65b88c29c918a9de4221bb..748e2e806ec1eab10252d811648f0d4a87825d4e 100644 --- a/drivers/gpu/msm/adreno_a6xx_snapshot.c +++ b/drivers/gpu/msm/adreno_a6xx_snapshot.c @@ -1149,8 +1149,7 @@ static size_t a6xx_snapshot_dbgc_debugbus_block(struct kgsl_device *device, block_id = block->block_id; /* GMU_GX data is read using the GMU_CX block id on A630 */ - if ((adreno_is_a630(adreno_dev) || adreno_is_a615(adreno_dev) || - adreno_is_a616(adreno_dev)) && + if ((adreno_is_a630(adreno_dev) || adreno_is_a615_family(adreno_dev)) && (block_id == A6XX_DBGBUS_GMU_GX)) block_id = A6XX_DBGBUS_GMU_CX; @@ -1560,7 +1559,7 @@ void a6xx_snapshot(struct adreno_device *adreno_dev, snapshot, a6xx_snapshot_registers, &a6xx_reg_list[i]); } - if (adreno_is_a615(adreno_dev) || adreno_is_a630(adreno_dev)) + if (adreno_is_a615_family(adreno_dev) || adreno_is_a630(adreno_dev)) adreno_snapshot_registers(device, snapshot, a630_rscc_snapshot_registers, ARRAY_SIZE(a630_rscc_snapshot_registers) / 2); diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c index 6876796bf124ba4eb829873c694b26ac9be8a0f0..a7699156a2b8fb72e046af9a651431a786b45102 100644 --- a/drivers/gpu/msm/adreno_drawctxt.c +++ b/drivers/gpu/msm/adreno_drawctxt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -472,6 +472,7 @@ void adreno_drawctxt_detach(struct kgsl_context *context) { struct kgsl_device *device; struct adreno_device *adreno_dev; + struct adreno_gpudev *gpudev; struct adreno_context *drawctxt; struct adreno_ringbuffer *rb; int ret, count, i; @@ -482,6 +483,7 @@ void adreno_drawctxt_detach(struct kgsl_context *context) device = context->device; adreno_dev = ADRENO_DEVICE(device); + gpudev = ADRENO_GPU_DEVICE(adreno_dev); drawctxt = ADRENO_CONTEXT(context); rb = drawctxt->rb; @@ -562,6 +564,9 @@ void adreno_drawctxt_detach(struct kgsl_context *context) mutex_unlock(&device->mutex); + if (gpudev->preemption_context_destroy) + gpudev->preemption_context_destroy(context); + /* wake threads waiting to submit commands from this context */ wake_up_all(&drawctxt->waiting); wake_up_all(&drawctxt->wq); @@ -570,18 +575,10 @@ void adreno_drawctxt_detach(struct kgsl_context *context) void adreno_drawctxt_destroy(struct kgsl_context *context) { struct adreno_context *drawctxt; - struct adreno_device *adreno_dev; - struct adreno_gpudev *gpudev; if (context == NULL) return; - adreno_dev = ADRENO_DEVICE(context->device); - gpudev = ADRENO_GPU_DEVICE(adreno_dev); - - if (gpudev->preemption_context_destroy) - gpudev->preemption_context_destroy(context); - drawctxt = ADRENO_CONTEXT(context); kfree(drawctxt); } diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c index bf0751dba86ba19bfe060548cc73a854096ce751..e9f8947e9ffc4278c9a63cfc181775004c128816 100644 --- a/drivers/gpu/msm/kgsl_gmu.c +++ b/drivers/gpu/msm/kgsl_gmu.c @@ -38,6 +38,8 @@ MODULE_PARM_DESC(noacd, "Disable GPU ACD"); #define GMU_CONTEXT_KERNEL 1 #define GMU_KERNEL_ENTRIES 16 +#define GMU_CM3_CFG_NONMASKINTR_SHIFT 9 + struct gmu_iommu_context { const char *name; struct device *dev; @@ -80,6 +82,8 @@ struct gmu_iommu_context gmu_ctx[] = { static struct gmu_memdesc gmu_kmem_entries[GMU_KERNEL_ENTRIES]; static unsigned long gmu_kmem_bitmap; static unsigned int num_uncached_entries; + +static void gmu_snapshot(struct kgsl_device *device); static void gmu_remove(struct kgsl_device *device); static int _gmu_iommu_fault_handler(struct device *dev, @@ -459,8 +463,7 @@ static int gmu_memory_probe(struct kgsl_device *device, } /* Allocates & maps GMU crash dump memory */ - if (adreno_is_a630(adreno_dev) || adreno_is_a615(adreno_dev) || - adreno_is_a616(adreno_dev)) { + if (adreno_is_a630(adreno_dev) || adreno_is_a615_family(adreno_dev)) { gmu->dump_mem = allocate_gmu_kmem(gmu, GMU_NONCACHED_KERNEL, DUMPMEM_SIZE, (IOMMU_READ | IOMMU_WRITE)); if (IS_ERR(gmu->dump_mem)) { @@ -541,9 +544,7 @@ static int gmu_dcvs_set(struct kgsl_device *device, dev_err_ratelimited(&gmu->pdev->dev, "Failed to set GPU perf idx %d, bw idx %d\n", req.freq, req.bw); - - adreno_set_gpu_fault(adreno_dev, ADRENO_GMU_FAULT); - adreno_dispatcher_schedule(device); + gmu_snapshot(device); } /* indicate actual clock change */ @@ -819,6 +820,38 @@ static void build_bwtable_cmd_cache(struct gmu_device *gmu) votes->cnoc_votes.cmd_data[i][j]; } +static int gmu_acd_probe(struct gmu_device *gmu, struct device_node *node) +{ + struct hfi_acd_table_cmd *cmd = &gmu->hfi.acd_tbl_cmd; + struct device_node *acd_node; + + acd_node = of_find_node_by_name(node, "qcom,gpu-acd-table"); + if (!acd_node) + return -ENODEV; + + cmd->hdr = 0xFFFFFFFF; + cmd->version = HFI_ACD_INIT_VERSION; + cmd->enable_by_level = 0; + cmd->stride = 0; + cmd->num_levels = 0; + + of_property_read_u32(acd_node, "qcom,acd-stride", &cmd->stride); + if (!cmd->stride || cmd->stride > MAX_ACD_STRIDE) + return -EINVAL; + + of_property_read_u32(acd_node, "qcom,acd-num-levels", &cmd->num_levels); + if (!cmd->num_levels || cmd->num_levels > MAX_ACD_NUM_LEVELS) + return -EINVAL; + + of_property_read_u32(acd_node, "qcom,acd-enable-by-level", + &cmd->enable_by_level); + if (hweight32(cmd->enable_by_level) != cmd->num_levels) + return -EINVAL; + + return of_property_read_u32_array(acd_node, "qcom,acd-data", + cmd->data, cmd->stride * cmd->num_levels); +} + /* * gmu_bus_vote_init - initialized RPMh votes needed for bw scaling by GMU. * @gmu: Pointer to GMU device @@ -895,6 +928,24 @@ static int gmu_rpmh_init(struct kgsl_device *device, return rpmh_arc_votes_init(device, gmu, &cx_arc, &mx_arc, GMU_ARC_VOTE); } +static void send_nmi_to_gmu(struct adreno_device *adreno_dev) +{ + /* Mask so there's no interrupt caused by NMI */ + adreno_write_gmureg(adreno_dev, + ADRENO_REG_GMU_GMU2HOST_INTR_MASK, 0xFFFFFFFF); + + /* Make sure the interrupt is masked before causing it */ + wmb(); + adreno_write_gmureg(adreno_dev, + ADRENO_REG_GMU_NMI_CONTROL_STATUS, 0); + adreno_write_gmureg(adreno_dev, + ADRENO_REG_GMU_CM3_CFG, + (1 << GMU_CM3_CFG_NONMASKINTR_SHIFT)); + + /* Make sure the NMI is invoked before we proceed*/ + wmb(); +} + static irqreturn_t gmu_irq_handler(int irq, void *data) { struct kgsl_device *device = data; @@ -916,6 +967,13 @@ static irqreturn_t gmu_irq_handler(int irq, void *data) ADRENO_REG_GMU_AO_HOST_INTERRUPT_MASK, (mask | GMU_INT_WDOG_BITE)); + send_nmi_to_gmu(adreno_dev); + /* + * There is sufficient delay for the GMU to have finished + * handling the NMI before snapshot is taken, as the fault + * worker is scheduled below. + */ + dev_err_ratelimited(&gmu->pdev->dev, "GMU watchdog expired interrupt received\n"); adreno_set_gpu_fault(adreno_dev, ADRENO_GMU_FAULT); @@ -1309,9 +1367,6 @@ static int gmu_probe(struct kgsl_device *device, struct device_node *node) disable_irq(hfi->hfi_interrupt_num); tasklet_init(&hfi->tasklet, hfi_receiver, (unsigned long) gmu); - INIT_LIST_HEAD(&hfi->msglist); - spin_lock_init(&hfi->msglock); - spin_lock_init(&hfi->read_queue_lock); hfi->kgsldev = device; /* Retrieves GMU/GPU power level configurations*/ @@ -1325,7 +1380,6 @@ static int gmu_probe(struct kgsl_device *device, struct device_node *node) int j = gmu->num_gpupwrlevels - 1 - i; gmu->gpu_freqs[i] = pwr->pwrlevels[j].gpu_freq; - gmu->acd_dvm_vals[i] = pwr->pwrlevels[j].acd_dvm_val; } /* Initializes GPU b/w levels configuration */ @@ -1358,10 +1412,15 @@ static int gmu_probe(struct kgsl_device *device, struct device_node *node) gmu->idle_level = GPU_HW_ACTIVE; if (ADRENO_FEATURE(adreno_dev, ADRENO_ACD) && !noacd) { - ret = gmu_aop_mailbox_init(device, gmu); - if (ret) - dev_err(&gmu->pdev->dev, + if (!gmu_acd_probe(gmu, node)) { + /* Init the AOP mailbox if we have a valid ACD table */ + ret = gmu_aop_mailbox_init(device, gmu); + if (ret) + dev_err(&gmu->pdev->dev, "AOP mailbox init failed: %d\n", ret); + } else + dev_err(&gmu->pdev->dev, + "ACD probe failed: missing or invalid table\n"); } /* disable LM if the feature is not enabled */ @@ -1514,19 +1573,8 @@ static void gmu_snapshot(struct kgsl_device *device) struct gmu_dev_ops *gmu_dev_ops = GMU_DEVICE_OPS(device); struct gmu_device *gmu = KGSL_GMU_DEVICE(device); - /* Mask so there's no interrupt caused by NMI */ - adreno_write_gmureg(adreno_dev, - ADRENO_REG_GMU_GMU2HOST_INTR_MASK, 0xFFFFFFFF); - - /* Make sure the interrupt is masked before causing it */ - wmb(); - adreno_write_gmureg(adreno_dev, - ADRENO_REG_GMU_NMI_CONTROL_STATUS, 0); - adreno_write_gmureg(adreno_dev, - ADRENO_REG_GMU_CM3_CFG, (1 << 9)); - + send_nmi_to_gmu(adreno_dev); /* Wait for the NMI to be handled */ - wmb(); udelay(100); kgsl_device_snapshot(device, NULL, true); diff --git a/drivers/gpu/msm/kgsl_gmu.h b/drivers/gpu/msm/kgsl_gmu.h index 8619b9327165aa58b287697d6e78be1f1ef35020..cb211ee113eb2f70cc9cf7176d863816aeb7cfae 100644 --- a/drivers/gpu/msm/kgsl_gmu.h +++ b/drivers/gpu/msm/kgsl_gmu.h @@ -18,7 +18,7 @@ #include #include "kgsl_hfi.h" -#define MAX_GMUFW_SIZE 0x2000 /* in bytes */ +#define MAX_GMUFW_SIZE 0x8000 /* in bytes */ #define BWMEM_SIZE (12 + (4 * NUM_BW_LEVELS)) /*in bytes*/ @@ -157,7 +157,6 @@ struct kgsl_mailbox { * @ccl: CNOC BW scaling client * @idle_level: Minimal GPU idle power level * @fault_count: GMU fault count - * @acd_dvm_vals: Table of DVM values that correspond to frequency levels * @mailbox: Messages to AOP for ACD enable/disable go through this */ struct gmu_device { @@ -190,7 +189,6 @@ struct gmu_device { unsigned int ccl; unsigned int idle_level; unsigned int fault_count; - unsigned int acd_dvm_vals[MAX_GX_LEVELS]; struct kgsl_mailbox mailbox; }; diff --git a/drivers/gpu/msm/kgsl_gmu_core.c b/drivers/gpu/msm/kgsl_gmu_core.c index b347f8dd24f41bf2848a748a3d335e39851ddf4b..b61a0bf50891acf586ad33a246a11e322f286894 100644 --- a/drivers/gpu/msm/kgsl_gmu_core.c +++ b/drivers/gpu/msm/kgsl_gmu_core.c @@ -117,7 +117,9 @@ bool gmu_core_scales_bandwidth(struct kgsl_device *device) if (device->gmu_core.type == GMU_CORE_TYPE_PCC) return false; else - return gmu_core_gpmu_isenabled(device); + return gmu_core_gpmu_isenabled(device) && + (adreno_is_a640(ADRENO_DEVICE(device)) || + adreno_is_a680(ADRENO_DEVICE(device))); } int gmu_core_start(struct kgsl_device *device) diff --git a/drivers/gpu/msm/kgsl_hfi.c b/drivers/gpu/msm/kgsl_hfi.c index 5f1ed35f5760abc2986299c977d8568859219985..b83344457f5a101b1f735f5235aa71288f5b3ff0 100644 --- a/drivers/gpu/msm/kgsl_hfi.c +++ b/drivers/gpu/msm/kgsl_hfi.c @@ -16,6 +16,7 @@ #include "kgsl_gmu.h" #include "adreno.h" #include "kgsl_trace.h" +#include "kgsl_pwrctrl.h" #define HFI_QUEUE_OFFSET(i) \ (ALIGN(sizeof(struct hfi_queue_table), SZ_16) + \ @@ -46,13 +47,13 @@ (((minor) & 0x7FFFFF) << 5) | \ ((branch) & 0x1F)) -static void hfi_process_queue(struct gmu_device *gmu, uint32_t queue_idx); +static void hfi_process_queue(struct gmu_device *gmu, uint32_t queue_idx, + struct pending_cmd *ret_cmd); /* Size in below functions are in unit of dwords */ static int hfi_queue_read(struct gmu_device *gmu, uint32_t queue_idx, unsigned int *output, unsigned int max_size) { - struct kgsl_hfi *hfi = &gmu->hfi; struct gmu_memdesc *mem_addr = gmu->hfi_mem; struct hfi_queue_table *tbl = mem_addr->hostptr; struct hfi_queue_header *hdr = &tbl->qhdr[queue_idx]; @@ -65,8 +66,6 @@ static int hfi_queue_read(struct gmu_device *gmu, uint32_t queue_idx, if (hdr->status == HFI_QUEUE_STATUS_DISABLED) return -EINVAL; - spin_lock_bh(&hfi->read_queue_lock); - if (hdr->read_index == hdr->write_index) { hdr->rx_req = 1; result = -ENODATA; @@ -110,7 +109,6 @@ static int hfi_queue_read(struct gmu_device *gmu, uint32_t queue_idx, hdr->read_index = read; done: - spin_unlock_bh(&hfi->read_queue_lock); return result; } @@ -195,6 +193,7 @@ static int hfi_queue_write(struct gmu_device *gmu, uint32_t queue_idx, void hfi_init(struct kgsl_hfi *hfi, struct gmu_memdesc *mem_addr, uint32_t queue_sz_bytes) { + struct adreno_device *adreno_dev = ADRENO_DEVICE(hfi->kgsldev); int i; struct hfi_queue_table *tbl; struct hfi_queue_header *hdr; @@ -209,6 +208,17 @@ void hfi_init(struct kgsl_hfi *hfi, struct gmu_memdesc *mem_addr, { HFI_DSP_IDX_0, HFI_DSP_PRI_0, HFI_QUEUE_STATUS_DISABLED }, }; + /* + * Overwrite the queue IDs for A630, A615 and A616 as they use + * legacy firmware. Legacy firmware has different queue IDs for + * message, debug and dispatch queues. + */ + if (adreno_is_a630(adreno_dev) || adreno_is_a615_family(adreno_dev)) { + queue[HFI_MSG_ID].idx = HFI_MSG_IDX_LEGACY; + queue[HFI_DBG_ID].idx = HFI_DBG_IDX_LEGACY; + queue[HFI_DSP_ID_0].idx = HFI_DSP_IDX_0_LEGACY; + } + /* Fill Table Header */ tbl = mem_addr->hostptr; tbl->qtbl_hdr.version = 0; @@ -241,39 +251,27 @@ void hfi_init(struct kgsl_hfi *hfi, struct gmu_memdesc *mem_addr, #define HDR_CMP_SEQNUM(out_hdr, in_hdr) \ (MSG_HDR_GET_SEQNUM(out_hdr) == MSG_HDR_GET_SEQNUM(in_hdr)) -static void receive_ack_cmd(struct gmu_device *gmu, void *rcvd) +static void receive_ack_cmd(struct gmu_device *gmu, void *rcvd, + struct pending_cmd *ret_cmd) { uint32_t *ack = rcvd; uint32_t hdr = ack[0]; uint32_t req_hdr = ack[1]; struct kgsl_hfi *hfi = &gmu->hfi; - struct pending_cmd *cmd = NULL; - uint32_t waiters[64], i = 0, j; trace_kgsl_hfi_receive(MSG_HDR_GET_ID(req_hdr), MSG_HDR_GET_SIZE(req_hdr), MSG_HDR_GET_SEQNUM(req_hdr)); - spin_lock_bh(&hfi->msglock); - list_for_each_entry(cmd, &hfi->msglist, node) { - if (HDR_CMP_SEQNUM(cmd->sent_hdr, req_hdr)) { - memcpy(&cmd->results, ack, MSG_HDR_GET_SIZE(hdr) << 2); - complete(&cmd->msg_complete); - spin_unlock_bh(&hfi->msglock); - return; - } - if (i < 64) - waiters[i++] = cmd->sent_hdr; + if (HDR_CMP_SEQNUM(ret_cmd->sent_hdr, req_hdr)) { + memcpy(&ret_cmd->results, ack, MSG_HDR_GET_SIZE(hdr) << 2); + return; } - spin_unlock_bh(&hfi->msglock); + /* Didn't find the sender, list the waiter */ dev_err_ratelimited(&gmu->pdev->dev, - "HFI ACK: Cannot find sender for 0x%8.8X\n", req_hdr); - /* Didn't find the sender, list all the waiters */ - for (j = 0; j < i && j < 64; j++) { - dev_err_ratelimited(&gmu->pdev->dev, - "HFI ACK: Waiters: 0x%8.8X\n", waiters[j]); - } + "HFI ACK: Cannot find sender for 0x%8.8x Waiter: 0x%8.8x\n", + req_hdr, ret_cmd->sent_hdr); adreno_set_gpu_fault(ADRENO_DEVICE(hfi->kgsldev), ADRENO_GMU_FAULT); adreno_dispatcher_schedule(hfi->kgsldev); @@ -282,6 +280,28 @@ static void receive_ack_cmd(struct gmu_device *gmu, void *rcvd) #define MSG_HDR_SET_SEQNUM(hdr, num) \ (((hdr) & 0xFFFFF) | ((num) << 20)) +static int poll_adreno_gmu_reg(struct adreno_device *adreno_dev, + enum adreno_regs offset_name, unsigned int expected_val, + unsigned int mask, unsigned int timeout_ms) +{ + unsigned int val; + unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); + + while (time_is_after_jiffies(timeout)) { + adreno_read_gmureg(adreno_dev, offset_name, &val); + if ((val & mask) == expected_val) + return 0; + usleep_range(10, 100); + } + + /* Check one last time */ + adreno_read_gmureg(adreno_dev, offset_name, &val); + if ((val & mask) == expected_val) + return 0; + + return -ETIMEDOUT; +} + static int hfi_send_cmd(struct gmu_device *gmu, uint32_t queue_idx, void *data, struct pending_cmd *ret_cmd) { @@ -289,42 +309,34 @@ static int hfi_send_cmd(struct gmu_device *gmu, uint32_t queue_idx, uint32_t *cmd = data; struct kgsl_hfi *hfi = &gmu->hfi; unsigned int seqnum = atomic_inc_return(&hfi->seqnum); + struct adreno_device *adreno_dev = ADRENO_DEVICE(hfi->kgsldev); *cmd = MSG_HDR_SET_SEQNUM(*cmd, seqnum); if (ret_cmd == NULL) return hfi_queue_write(gmu, queue_idx, cmd); - init_completion(&ret_cmd->msg_complete); ret_cmd->sent_hdr = cmd[0]; - spin_lock_bh(&hfi->msglock); - list_add_tail(&ret_cmd->node, &hfi->msglist); - spin_unlock_bh(&hfi->msglock); - rc = hfi_queue_write(gmu, queue_idx, cmd); if (rc) - goto done; + return rc; + + rc = poll_adreno_gmu_reg(adreno_dev, ADRENO_REG_GMU_GMU2HOST_INTR_INFO, + HFI_IRQ_MSGQ_MASK, HFI_IRQ_MSGQ_MASK, HFI_RSP_TIMEOUT); + + if (rc) { + dev_err(&gmu->pdev->dev, + "Timed out waiting on ack for 0x%8.8x (id %d, sequence %d)\n", + cmd[0], MSG_HDR_GET_ID(*cmd), MSG_HDR_GET_SEQNUM(*cmd)); + return rc; + } + + /* Clear the interrupt */ + adreno_write_gmureg(adreno_dev, ADRENO_REG_GMU_GMU2HOST_INTR_CLR, + HFI_IRQ_MSGQ_MASK); + + hfi_process_queue(gmu, HFI_MSG_ID, ret_cmd); - rc = wait_for_completion_timeout( - &ret_cmd->msg_complete, - msecs_to_jiffies(HFI_RSP_TIMEOUT)); - if (!rc) { - /* Check one more time to make sure there is no response */ - hfi_process_queue(gmu, HFI_MSG_ID); - if (!completion_done(&ret_cmd->msg_complete)) { - dev_err(&gmu->pdev->dev, - "Timed out waiting on ack for 0x%8.8x (id %d, sequence %d)\n", - cmd[0], - MSG_HDR_GET_ID(*cmd), - MSG_HDR_GET_SEQNUM(*cmd)); - rc = -ETIMEDOUT; - } - } else - rc = 0; -done: - spin_lock_bh(&hfi->msglock); - list_del(&ret_cmd->node); - spin_unlock_bh(&hfi->msglock); return rc; } @@ -488,7 +500,8 @@ static int hfi_send_dcvstbl(struct gmu_device *gmu) for (i = 0; i < gmu->num_gpupwrlevels; i++) { cmd.gx_votes[i].vote = gmu->rpmh_votes.gx_votes[i]; - cmd.gx_votes[i].acd = gmu->acd_dvm_vals[i]; + /* Hardcode this to the max threshold since it is not used */ + cmd.gx_votes[i].acd = 0xFFFFFFFF; /* Divide by 1000 to convert to kHz */ cmd.gx_votes[i].freq = gmu->gpu_freqs[i] / 1000; } @@ -510,6 +523,15 @@ static int hfi_send_bwtbl(struct gmu_device *gmu) return hfi_send_generic_req(gmu, HFI_CMD_ID, cmd); } +static int hfi_send_acd_tbl(struct gmu_device *gmu) +{ + struct hfi_acd_table_cmd *cmd = &gmu->hfi.acd_tbl_cmd; + + cmd->hdr = CMD_MSG_HDR(H2F_MSG_ACD_TBL, sizeof(*cmd)); + + return hfi_send_generic_req(gmu, HFI_CMD_IDX, cmd); +} + static int hfi_send_test(struct gmu_device *gmu) { struct hfi_test_cmd cmd = { @@ -537,11 +559,12 @@ static void receive_debug_req(struct gmu_device *gmu, void *rcvd) cmd->type, cmd->timestamp, cmd->data); } -static void hfi_v1_receiver(struct gmu_device *gmu, uint32_t *rcvd) +static void hfi_v1_receiver(struct gmu_device *gmu, uint32_t *rcvd, + struct pending_cmd *ret_cmd) { /* V1 ACK Handler */ if (MSG_HDR_GET_TYPE(rcvd[0]) == HFI_V1_MSG_ACK) { - receive_ack_cmd(gmu, rcvd); + receive_ack_cmd(gmu, rcvd, ret_cmd); return; } @@ -561,20 +584,21 @@ static void hfi_v1_receiver(struct gmu_device *gmu, uint32_t *rcvd) } } -static void hfi_process_queue(struct gmu_device *gmu, uint32_t queue_idx) +static void hfi_process_queue(struct gmu_device *gmu, uint32_t queue_idx, + struct pending_cmd *ret_cmd) { uint32_t rcvd[MAX_RCVD_SIZE]; while (hfi_queue_read(gmu, queue_idx, rcvd, sizeof(rcvd)) > 0) { /* Special case if we're v1 */ if (HFI_VER_MAJOR(&gmu->hfi) < 2) { - hfi_v1_receiver(gmu, rcvd); + hfi_v1_receiver(gmu, rcvd, ret_cmd); continue; } /* V2 ACK Handler */ if (MSG_HDR_GET_TYPE(rcvd[0]) == HFI_MSG_ACK) { - receive_ack_cmd(gmu, rcvd); + receive_ack_cmd(gmu, rcvd, ret_cmd); continue; } @@ -597,9 +621,8 @@ static void hfi_process_queue(struct gmu_device *gmu, uint32_t queue_idx) void hfi_receiver(unsigned long data) { - /* Process all read (firmware to host) queues */ - hfi_process_queue((struct gmu_device *) data, HFI_MSG_ID); - hfi_process_queue((struct gmu_device *) data, HFI_DBG_ID); + /* Process all asynchronous read (firmware to host) queues */ + hfi_process_queue((struct gmu_device *) data, HFI_DBG_ID, NULL); } #define GMU_VER_MAJOR(ver) (((ver) >> 28) & 0xF) @@ -649,8 +672,19 @@ static int hfi_verify_fw_version(struct kgsl_device *device, return 0; } -/* Levels greater than or equal to LM_DCVS_LEVEL are subject to throttling */ -#define LM_DCVS_LEVEL 4 +static int hfi_send_acd_feature_ctrl(struct gmu_device *gmu, + struct adreno_device *adreno_dev) +{ + int ret = 0; + + if (test_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag)) { + ret = hfi_send_acd_tbl(gmu); + if (!ret) + ret = hfi_send_feature_ctrl(gmu, HFI_FEATURE_ACD, 1, 0); + } + + return ret; +} int hfi_start(struct kgsl_device *device, struct gmu_device *gmu, uint32_t boot_state) @@ -706,19 +740,16 @@ int hfi_start(struct kgsl_device *device, */ if (HFI_VER_MAJOR(&gmu->hfi) >= 2) { result = hfi_send_feature_ctrl(gmu, HFI_FEATURE_ECP, 0, 0); - if (test_bit(ADRENO_ACD_CTRL, &adreno_dev->pwrctrl_flag)) - result |= hfi_send_feature_ctrl(gmu, - HFI_FEATURE_ACD, 1, 0); + if (result) + return result; + result = hfi_send_acd_feature_ctrl(gmu, adreno_dev); if (result) return result; if (test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) { - /* We want all bits starting at LM_DCVS_LEVEL to be 1 */ - int lm_data = -1 << (LM_DCVS_LEVEL - 1); - - result = hfi_send_feature_ctrl(gmu, - HFI_FEATURE_LM, 1, lm_data); + result = hfi_send_feature_ctrl(gmu, HFI_FEATURE_LM, 1, + device->pwrctrl.throttle_mask); if (result) return result; } @@ -831,7 +862,7 @@ irqreturn_t hfi_irq_handler(int irq, void *data) adreno_write_gmureg(ADRENO_DEVICE(device), ADRENO_REG_GMU_GMU2HOST_INTR_CLR, status); - if (status & HFI_IRQ_MSGQ_MASK) + if (status & HFI_IRQ_DBGQ_MASK) tasklet_hi_schedule(&hfi->tasklet); if (status & HFI_IRQ_CM3_FAULT_MASK) { dev_err_ratelimited(&gmu->pdev->dev, diff --git a/drivers/gpu/msm/kgsl_hfi.h b/drivers/gpu/msm/kgsl_hfi.h index d7e7fa7c0a30ef2247317403adacf5c2fc8bf925..b5121d747165394a31a4fab0195e663a4869c1ef 100644 --- a/drivers/gpu/msm/kgsl_hfi.h +++ b/drivers/gpu/msm/kgsl_hfi.h @@ -42,6 +42,11 @@ struct hfi_queue_table; #define HFI_DSP_IDX_BASE 3 #define HFI_DSP_IDX_0 3 +#define HFI_CMD_IDX_LEGACY 0 +#define HFI_DSP_IDX_0_LEGACY 1 +#define HFI_MSG_IDX_LEGACY 4 +#define HFI_DBG_IDX_LEGACY 5 + #define HFI_QUEUE_STATUS_DISABLED 0 #define HFI_QUEUE_STATUS_ENABLED 1 @@ -51,7 +56,7 @@ struct hfi_queue_table; #define HFI_DBG_PRI 40 #define HFI_DSP_PRI_0 20 -#define HFI_RSP_TIMEOUT 5000 /* msec */ +#define HFI_RSP_TIMEOUT 100 /* msec */ #define HFI_H2F_CMD_IRQ_MASK BIT(0) #define HFI_IRQ_MSGQ_MASK BIT(0) @@ -59,8 +64,7 @@ struct hfi_queue_table; #define HFI_IRQ_DBGQ_MASK BIT(2) #define HFI_IRQ_CM3_FAULT_MASK BIT(15) #define HFI_IRQ_OOB_MASK GENMASK(31, 16) -#define HFI_IRQ_MASK (HFI_IRQ_MSGQ_MASK |\ - HFI_IRQ_SIDEMSGQ_MASK |\ +#define HFI_IRQ_MASK (HFI_IRQ_SIDEMSGQ_MASK |\ HFI_IRQ_DBGQ_MASK |\ HFI_IRQ_CM3_FAULT_MASK) @@ -172,6 +176,7 @@ enum hfi_msg_type { #define H2F_MSG_BW_VOTE_TBL 3 #define H2F_MSG_PERF_TBL 4 #define H2F_MSG_TEST 5 +#define H2F_MSG_ACD_TBL 7 #define H2F_MSG_START 10 #define H2F_MSG_FEATURE_CTRL 11 #define H2F_MSG_GET_VALUE 12 @@ -270,6 +275,20 @@ struct hfi_dcvstable_cmd { struct opp_desc cx_votes[MAX_CX_LEVELS]; }; +#define HFI_ACD_INIT_VERSION 1 +#define MAX_ACD_STRIDE 2 +#define MAX_ACD_NUM_LEVELS 6 + +/* H2F */ +struct hfi_acd_table_cmd { + uint32_t hdr; + uint32_t version; + uint32_t enable_by_level; + uint32_t stride; + uint32_t num_levels; + uint32_t data[MAX_ACD_NUM_LEVELS * MAX_ACD_STRIDE]; +}; + /* H2F */ struct hfi_test_cmd { uint32_t hdr; @@ -582,14 +601,10 @@ struct hfi_context_bad_reply_cmd { /** * struct pending_cmd - data structure to track outstanding HFI * command messages - * @msg_complete: a blocking mechanism for sender to wait for ACK - * @node: a node in pending message queue * @sent_hdr: copy of outgoing header for response comparison * @results: the payload of received return message (ACK) */ struct pending_cmd { - struct completion msg_complete; - struct list_head node; uint32_t sent_hdr; uint32_t results[MAX_RCVD_SIZE]; }; @@ -598,28 +613,23 @@ struct pending_cmd { * struct kgsl_hfi - HFI control structure * @kgsldev: Point to the kgsl device * @hfi_interrupt_num: number of GMU asserted HFI interrupt - * @msglock: spinlock to protect access to outstanding command message list - * @read_queue_lock: spinlock to protect against concurrent reading of queues * @cmdq_mutex: mutex to protect command queue access from multiple senders - * @msglist: outstanding command message list. Each message in the list - * is waiting for ACK from GMU * @tasklet: the thread handling received messages from GMU * @version: HFI version number provided * @seqnum: atomic counter that is incremented for each message sent. The * value of the counter is used as sequence number for HFI message * @bwtbl_cmd: HFI BW table buffer + * @acd_tbl_cmd: HFI table for ACD data */ struct kgsl_hfi { struct kgsl_device *kgsldev; int hfi_interrupt_num; - spinlock_t msglock; - spinlock_t read_queue_lock; struct mutex cmdq_mutex; - struct list_head msglist; struct tasklet_struct tasklet; uint32_t version; atomic_t seqnum; struct hfi_bwtable_cmd bwtbl_cmd; + struct hfi_acd_table_cmd acd_tbl_cmd; }; struct gmu_device; diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index d0b0c8d59064c71c2989a22ab22f7c60b05c0e3b..1c6a17e2aef474ae93cc1095d0114c8d60da63d7 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -1182,7 +1182,7 @@ void _enable_gpuhtw_llc(struct kgsl_mmu *mmu, struct kgsl_iommu_pt *iommu_pt) return; /* Domain attribute to enable system cache for GPU pagetable walks */ - if (adreno_is_a640(adreno_dev)) + if (adreno_is_a640(adreno_dev) || adreno_is_a608(adreno_dev)) ret = iommu_domain_set_attr(iommu_pt->domain, DOMAIN_ATTR_USE_LLC_NWA, &gpuhtw_llc_enable); else @@ -2090,6 +2090,8 @@ kgsl_iommu_get_current_ttbr0(struct kgsl_mmu *mmu) { u64 val; struct kgsl_iommu *iommu = _IOMMU_PRIV(mmu); + struct kgsl_iommu_context *ctx = &iommu->ctx[KGSL_IOMMU_CONTEXT_USER]; + /* * We cannot enable or disable the clocks in interrupt context, this * function is called from interrupt context if there is an axi error @@ -2097,9 +2099,11 @@ kgsl_iommu_get_current_ttbr0(struct kgsl_mmu *mmu) if (in_interrupt()) return 0; + if (ctx->regbase == NULL) + return 0; + kgsl_iommu_enable_clk(mmu); - val = KGSL_IOMMU_GET_CTX_REG_Q(&iommu->ctx[KGSL_IOMMU_CONTEXT_USER], - TTBR0); + val = KGSL_IOMMU_GET_CTX_REG_Q(ctx, TTBR0); kgsl_iommu_disable_clk(mmu); return val; } diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index eac25deeb71a942d248c901fbaf36a1ac2f2c75c..95190163a4ca3246ac952d9a8909db6d546cffaa 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -2839,6 +2839,12 @@ _aware(struct kgsl_device *device) status = gmu_core_start(device); break; case KGSL_STATE_INIT: + /* if GMU already in FAULT */ + if (gmu_core_isenabled(device) && + test_bit(GMU_FAULT, &device->gmu_core.flags)) { + status = -EINVAL; + break; + } status = kgsl_pwrctrl_enable(device); break; /* The following 3 cases shouldn't occur, but don't panic. */ diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h index 0a78aba0657eab083b57848552ed28666589262c..421e8d2dd8a4cba1a815efa3f9eacff5c4f4cf89 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.h +++ b/drivers/gpu/msm/kgsl_pwrctrl.h @@ -107,14 +107,12 @@ struct kgsl_pwr_constraint { * @bus_freq: Bus bandwidth vote index * @bus_min: Min bus index @gpu_freq * @bus_max: Max bus index @gpu_freq - * @acd_dvm_val: Register setting for ACD */ struct kgsl_pwrlevel { unsigned int gpu_freq; unsigned int bus_freq; unsigned int bus_min; unsigned int bus_max; - unsigned int acd_dvm_val; }; struct kgsl_regulator { @@ -137,6 +135,7 @@ struct kgsl_regulator { * @max_pwrlevel - maximum allowable powerlevel per the user * @min_pwrlevel - minimum allowable powerlevel per the user * @num_pwrlevels - number of available power levels + * @throttle_mask - LM throttle mask * @interval_timeout - timeout in jiffies to be idle before a power event * @clock_times - Each GPU frequency's accumulated active time in us * @regulators - array of pointers to kgsl_regulator structs @@ -196,6 +195,7 @@ struct kgsl_pwrctrl { unsigned int max_pwrlevel; unsigned int min_pwrlevel; unsigned int num_pwrlevels; + unsigned int throttle_mask; unsigned long interval_timeout; u64 clock_times[KGSL_MAX_PWRLEVELS]; struct kgsl_regulator regulators[KGSL_MAX_REGULATORS]; diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 376d52ac913e0abed45d057a0b1669b9a9f1add6..0b775c13c08ef1d1321e39d694be5c37336a64a3 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -123,4 +123,4 @@ obj-$(CONFIG_I2C_HID) += i2c-hid/ obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/ -obj-$(CONFIG_HID_QVR) += hid-qvr.o +obj-$(CONFIG_HID_QVR) += hid-qvr.o hid-trace.o diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 25b7bd56ae1156aa209980f65a00d2c5a6efebf2..1cb41992aaa1f650f89cbf5ace72bd46786d7abc 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -335,7 +335,8 @@ static int apple_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { - if (usage->hid == (HID_UP_CUSTOM | 0x0003)) { + if (usage->hid == (HID_UP_CUSTOM | 0x0003) || + usage->hid == (HID_UP_MSVENDOR | 0x0003)) { /* The fn key on Apple USB keyboards */ set_bit(EV_REP, hi->input->evbit); hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_FN); @@ -472,6 +473,12 @@ static const struct hid_device_id apple_devices[] = { .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_ANSI), .driver_data = APPLE_HAS_FN }, + { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_ANSI), + .driver_data = APPLE_HAS_FN }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_ANSI), + .driver_data = APPLE_HAS_FN }, + { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_ANSI), + .driver_data = APPLE_HAS_FN }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI), .driver_data = APPLE_HAS_FN }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO), diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 461a5f1b220cb122ee8a0e28f391a5949dccb91a..2e895bf5bd11498ed5d92acdc8993f1b6c2edf48 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -85,6 +85,7 @@ #define USB_DEVICE_ID_ANTON_TOUCH_PAD 0x3101 #define USB_VENDOR_ID_APPLE 0x05ac +#define BT_VENDOR_ID_APPLE 0x004c #define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304 #define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d #define USB_DEVICE_ID_APPLE_MAGICTRACKPAD 0x030e @@ -154,6 +155,7 @@ #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO 0x0256 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS 0x0257 #define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_ANSI 0x0267 +#define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_ANSI 0x026c #define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI 0x0290 #define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO 0x0291 #define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS 0x0292 @@ -528,6 +530,7 @@ #define USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0A4A 0x0a4a #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_VENDOR_ID_HUION 0x256c #define USB_DEVICE_ID_HUION_TABLET 0x006e @@ -923,6 +926,7 @@ #define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17 #define USB_DEVICE_ID_SAITEK_PS1000 0x0621 #define USB_DEVICE_ID_SAITEK_RAT7_OLD 0x0ccb +#define USB_DEVICE_ID_SAITEK_RAT7_CONTAGION 0x0ccd #define USB_DEVICE_ID_SAITEK_RAT7 0x0cd7 #define USB_DEVICE_ID_SAITEK_RAT9 0x0cfa #define USB_DEVICE_ID_SAITEK_MMO7 0x0cd0 diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c index 3d121d8ee980b28458021e591129ae369c813721..5d2d746e35f60aabeb951d3cbd27316ee0fcde03 100644 --- a/drivers/hid/hid-ntrig.c +++ b/drivers/hid/hid-ntrig.c @@ -955,6 +955,8 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id) ret = sysfs_create_group(&hdev->dev.kobj, &ntrig_attribute_group); + if (ret) + hid_err(hdev, "cannot create sysfs group\n"); return 0; err_free: diff --git a/drivers/hid/hid-qvr.c b/drivers/hid/hid-qvr.c index 7e1eac068d5120a066491ed9715d88964be0ba4b..52ee0487b37f0de5a179c5176c491b95dc94fbbc 100644 --- a/drivers/hid/hid-qvr.c +++ b/drivers/hid/hid-qvr.c @@ -37,6 +37,7 @@ #include #include "hid-ids.h" #include "hid-qvr.h" +#include "hid-trace.h" static struct dma_buf *qvr_buf; static void *vaddr; @@ -123,6 +124,9 @@ int qvr_send_package_wrap(u8 *message, int msize, struct hid_device *hid) data->my = imuData.my0; data->mz = -imuData.mz0; + trace_qvr_recv_sensor("gyro", data->gts, data->gx, data->gy, data->gz); + trace_qvr_recv_sensor("accel", data->ats, data->ax, data->ay, data->az); + index_buf->most_recent_index = buf_index; buf_index = (buf_index == (8 - 1)) ? 0 : buf_index + 1; return 0; diff --git a/drivers/hid/hid-saitek.c b/drivers/hid/hid-saitek.c index 39e642686ff0466322cdacf7ea410fd6306932e5..683861f324e3cd6842f30016f4911b4b088d8a2a 100644 --- a/drivers/hid/hid-saitek.c +++ b/drivers/hid/hid-saitek.c @@ -183,6 +183,8 @@ static const struct hid_device_id saitek_devices[] = { .driver_data = SAITEK_RELEASE_MODE_RAT7 }, { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7), .driver_data = SAITEK_RELEASE_MODE_RAT7 }, + { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7_CONTAGION), + .driver_data = SAITEK_RELEASE_MODE_RAT7 }, { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT9), .driver_data = SAITEK_RELEASE_MODE_RAT7 }, { HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT9), diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index 25363fc571bcc285a009cffd4fb9ceaf7a28c24f..faba542d1b0741f8a21693e58626bcdf52533d6f 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -579,6 +579,28 @@ void sensor_hub_device_close(struct hid_sensor_hub_device *hsdev) } EXPORT_SYMBOL_GPL(sensor_hub_device_close); +static __u8 *sensor_hub_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) +{ + /* + * Checks if the report descriptor of Thinkpad Helix 2 has a logical + * minimum for magnetic flux axis greater than the maximum. + */ + if (hdev->product == USB_DEVICE_ID_TEXAS_INSTRUMENTS_LENOVO_YOGA && + *rsize == 2558 && rdesc[913] == 0x17 && rdesc[914] == 0x40 && + rdesc[915] == 0x81 && rdesc[916] == 0x08 && + rdesc[917] == 0x00 && rdesc[918] == 0x27 && + rdesc[921] == 0x07 && rdesc[922] == 0x00) { + /* Sets negative logical minimum for mag x, y and z */ + rdesc[914] = rdesc[935] = rdesc[956] = 0xc0; + rdesc[915] = rdesc[936] = rdesc[957] = 0x7e; + rdesc[916] = rdesc[937] = rdesc[958] = 0xf7; + rdesc[917] = rdesc[938] = rdesc[959] = 0xff; + } + + return rdesc; +} + static int sensor_hub_probe(struct hid_device *hdev, const struct hid_device_id *id) { @@ -742,6 +764,7 @@ static struct hid_driver sensor_hub_driver = { .probe = sensor_hub_probe, .remove = sensor_hub_remove, .raw_event = sensor_hub_raw_event, + .report_fixup = sensor_hub_report_fixup, #ifdef CONFIG_PM .suspend = sensor_hub_suspend, .resume = sensor_hub_resume, diff --git a/drivers/hid/hid-trace.c b/drivers/hid/hid-trace.c new file mode 100644 index 0000000000000000000000000000000000000000..b3afcb7a42029359c94f5a7ca06469202bec99c7 --- /dev/null +++ b/drivers/hid/hid-trace.c @@ -0,0 +1,17 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + + +/* Instantiate tracepoints */ +#define CREATE_TRACE_POINTS +#include "hid-trace.h" diff --git a/drivers/hid/hid-trace.h b/drivers/hid/hid-trace.h new file mode 100644 index 0000000000000000000000000000000000000000..4415055f01aaeea79bafef31d7cda085a00a48d1 --- /dev/null +++ b/drivers/hid/hid-trace.h @@ -0,0 +1,56 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#if !defined(_HID_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _HID_TRACE_H + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM hid +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE hid-trace + +#include + +TRACE_EVENT(qvr_recv_sensor, + TP_PROTO(char *sensor, uint64_t ts, s32 x, s32 y, s32 z), + TP_ARGS(sensor, ts, x, y, z), + TP_STRUCT__entry( + __field(char *, sensor) + __field(uint64_t, ts) + __field(int, x) + __field(int, y) + __field(int, z) + ), + TP_fast_assign( + __entry->sensor = sensor; + __entry->ts = ts; + __entry->x = x; + __entry->y = y; + __entry->z = z; + ), + TP_printk( + "%s - ts=%llu x=%d y=%d z=%d", + __entry->sensor, + __entry->ts, + __entry->x, + __entry->y, + __entry->z + ) + ); + +#endif /* _HID_TRACE_H */ + +/* This part must be outside protection */ +#include diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 90af938be5159ce57889004975a99d0623540b97..7ec886d4a332d3d1e2afb129a9681b7c7deb445f 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -99,6 +99,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0A4A, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL }, + { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6680, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C007, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077, HID_QUIRK_ALWAYS_POLL }, diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index c401b5b63f4c59c696acfcd21c6943b00b75ae54..4c72e68637c2831848df7c3fdaee8201b651f4d0 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -3212,8 +3212,14 @@ void wacom_setup_device_quirks(struct wacom *wacom) if (features->type >= INTUOSHT && features->type <= BAMBOO_PT) features->device_type |= WACOM_DEVICETYPE_PAD; - features->x_max = 4096; - features->y_max = 4096; + if (features->type == INTUOSHT2) { + features->x_max = features->x_max / 10; + features->y_max = features->y_max / 10; + } + else { + features->x_max = 4096; + features->y_max = 4096; + } } else if (features->pktlen == WACOM_PKGLEN_BBTOUCH) { features->device_type |= WACOM_DEVICETYPE_PAD; diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 05964347008d9c51c1457b65ddd9ef0d1815f584..d96b09fea8358162df586a20f706ba88e2de5491 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -541,11 +541,8 @@ static void reset_channel_cb(void *arg) channel->onchannel_callback = NULL; } -static int vmbus_close_internal(struct vmbus_channel *channel) +void vmbus_reset_channel_cb(struct vmbus_channel *channel) { - struct vmbus_channel_close_channel *msg; - int ret; - /* * vmbus_on_event(), running in the per-channel tasklet, can race * with vmbus_close_internal() in the case of SMP guest, e.g., when @@ -555,6 +552,29 @@ static int vmbus_close_internal(struct vmbus_channel *channel) */ tasklet_disable(&channel->callback_event); + channel->sc_creation_callback = NULL; + + /* Stop the callback asap */ + if (channel->target_cpu != get_cpu()) { + put_cpu(); + smp_call_function_single(channel->target_cpu, reset_channel_cb, + channel, true); + } else { + reset_channel_cb(channel); + put_cpu(); + } + + /* Re-enable tasklet for use on re-open */ + tasklet_enable(&channel->callback_event); +} + +static int vmbus_close_internal(struct vmbus_channel *channel) +{ + struct vmbus_channel_close_channel *msg; + int ret; + + vmbus_reset_channel_cb(channel); + /* * In case a device driver's probe() fails (e.g., * util_probe() -> vmbus_open() returns -ENOMEM) and the device is @@ -568,16 +588,6 @@ static int vmbus_close_internal(struct vmbus_channel *channel) } channel->state = CHANNEL_OPEN_STATE; - channel->sc_creation_callback = NULL; - /* Stop callback and cancel the timer asap */ - if (channel->target_cpu != get_cpu()) { - put_cpu(); - smp_call_function_single(channel->target_cpu, reset_channel_cb, - channel, true); - } else { - reset_channel_cb(channel); - put_cpu(); - } /* Send a closing message */ @@ -620,8 +630,6 @@ static int vmbus_close_internal(struct vmbus_channel *channel) get_order(channel->ringbuffer_pagecount * PAGE_SIZE)); out: - /* re-enable tasklet for use on re-open */ - tasklet_enable(&channel->callback_event); return ret; } diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 1939c0ca374152d50a68dd0c6122464bef9c2691..1700b4e7758d473282a69bdc95b15f0aa0ed7585 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -881,6 +881,12 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) return; } + /* + * Before setting channel->rescind in vmbus_rescind_cleanup(), we + * should make sure the channel callback is not running any more. + */ + vmbus_reset_channel_cb(channel); + /* * Now wait for offer handling to complete. */ diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index f41901f80b6456bf12f5cf0d1c98761520a3f68d..5449fc59b7f5ed2292b0d44d26e52b6a249152f2 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c @@ -74,6 +74,7 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, __u32 version) { int ret = 0; + unsigned int cur_cpu; struct vmbus_channel_initiate_contact *msg; unsigned long flags; @@ -96,9 +97,10 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, * the CPU attempting to connect may not be CPU 0. */ if (version >= VERSION_WIN8_1) { - msg->target_vcpu = - hv_cpu_number_to_vp_number(smp_processor_id()); - vmbus_connection.connect_cpu = smp_processor_id(); + cur_cpu = get_cpu(); + msg->target_vcpu = hv_cpu_number_to_vp_number(cur_cpu); + vmbus_connection.connect_cpu = cur_cpu; + put_cpu(); } else { msg->target_vcpu = 0; vmbus_connection.connect_cpu = 0; diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index 8267439dd1eec0ac32ed217edda4ff324f8e57fe..d8101cd28dfa3ff6c27e1db7ee5f0b3ff2950f76 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -196,6 +196,10 @@ int hv_synic_alloc(void) return 0; err: + /* + * Any memory allocations that succeeded will be freed when + * the caller cleans up by calling hv_synic_free() + */ return -ENOMEM; } @@ -208,12 +212,10 @@ void hv_synic_free(void) struct hv_per_cpu_context *hv_cpu = per_cpu_ptr(hv_context.cpu_context, cpu); - if (hv_cpu->synic_event_page) - free_page((unsigned long)hv_cpu->synic_event_page); - if (hv_cpu->synic_message_page) - free_page((unsigned long)hv_cpu->synic_message_page); - if (hv_cpu->post_msg_page) - free_page((unsigned long)hv_cpu->post_msg_page); + kfree(hv_cpu->clk_evt); + free_page((unsigned long)hv_cpu->synic_event_page); + free_page((unsigned long)hv_cpu->synic_message_page); + free_page((unsigned long)hv_cpu->post_msg_page); } kfree(hv_context.hv_numa_map); diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c index 9ef84998c7f382b114cd11d1c4ea04e7c916dda4..37db2eb66ed790624b0da69355d4414e24587269 100644 --- a/drivers/hwmon/adt7475.c +++ b/drivers/hwmon/adt7475.c @@ -303,14 +303,18 @@ static inline u16 volt2reg(int channel, long volt, u8 bypass_attn) return clamp_val(reg, 0, 1023) & (0xff << 2); } -static u16 adt7475_read_word(struct i2c_client *client, int reg) +static int adt7475_read_word(struct i2c_client *client, int reg) { - u16 val; + int val1, val2; - val = i2c_smbus_read_byte_data(client, reg); - val |= (i2c_smbus_read_byte_data(client, reg + 1) << 8); + val1 = i2c_smbus_read_byte_data(client, reg); + if (val1 < 0) + return val1; + val2 = i2c_smbus_read_byte_data(client, reg + 1); + if (val2 < 0) + return val2; - return val; + return val1 | (val2 << 8); } static void adt7475_write_word(struct i2c_client *client, int reg, u16 val) diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index e9e6aeabbf842ffd941e0476a185884adac85147..71d3445ba869c85654ae3dcaf3a5460e8fadb268 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c @@ -17,7 +17,7 @@ * Bi-directional Current/Power Monitor with I2C Interface * Datasheet: http://www.ti.com/product/ina230 * - * Copyright (C) 2012 Lothar Felten + * Copyright (C) 2012 Lothar Felten * Thanks to Jan Volkering * * This program is free software; you can redistribute it and/or modify @@ -329,6 +329,15 @@ static int ina2xx_set_shunt(struct ina2xx_data *data, long val) return 0; } +static ssize_t ina2xx_show_shunt(struct device *dev, + struct device_attribute *da, + char *buf) +{ + struct ina2xx_data *data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%li\n", data->rshunt); +} + static ssize_t ina2xx_store_shunt(struct device *dev, struct device_attribute *da, const char *buf, size_t count) @@ -403,7 +412,7 @@ static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ina2xx_show_value, NULL, /* shunt resistance */ static SENSOR_DEVICE_ATTR(shunt_resistor, S_IRUGO | S_IWUSR, - ina2xx_show_value, ina2xx_store_shunt, + ina2xx_show_shunt, ina2xx_store_shunt, INA2XX_CALIBRATION); /* update interval (ina226 only) */ diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c index f5f3f8cf57ea66d1a95bd4511d767611fb0fb338..ca9941fa741b7e04e971f70e4e8055e442e92c43 100644 --- a/drivers/hwmon/nct6775.c +++ b/drivers/hwmon/nct6775.c @@ -63,6 +63,7 @@ #include #include #include +#include #include "lm75.h" #define USE_ALTERNATE @@ -2642,6 +2643,7 @@ store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr, return err; if (val > NUM_TEMP) return -EINVAL; + val = array_index_nospec(val, NUM_TEMP + 1); if (val && (!(data->have_temp & BIT(val - 1)) || !data->temp_src[val - 1])) return -EINVAL; @@ -4107,7 +4109,7 @@ static int nct6775_probe(struct platform_device *pdev) * The temperature is already monitored if the respective bit in * is set. */ - for (i = 0; i < 32; i++) { + for (i = 0; i < 31; i++) { if (!(data->temp_mask & BIT(i + 1))) continue; if (!reg_temp_alternate[i]) diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c index ba736d11597428c9cede92412ed51a9d588c5b55..b004abe4f9a97815dd84b2a4ed50243a0c1fa6e9 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.c +++ b/drivers/hwtracing/coresight/coresight-etm4x.c @@ -1039,7 +1039,8 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id) pm_runtime_put(&adev->dev); etmdrvdata[drvdata->cpu] = drvdata; - dev_info(dev, "%s initialized\n", (char *)id->data); + dev_info(dev, "CPU%d: ETM v%d.%d initialized\n", + drvdata->cpu, drvdata->arch >> 4, drvdata->arch & 0xf); if (boot_enable) { coresight_enable(drvdata->csdev); @@ -1057,23 +1058,19 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id) return ret; } +#define ETM4x_AMBA_ID(pid) \ + { \ + .id = pid, \ + .mask = 0x000fffff, \ + } + static const struct amba_id etm4_ids[] = { - { /* ETM 4.0 - Cortex-A53 */ - .id = 0x000bb95d, - .mask = 0x000fffff, - .data = "ETM 4.0", - }, - { /* ETM 4.0 - Cortex-A57 */ - .id = 0x000bb95e, - .mask = 0x000fffff, - .data = "ETM 4.0", - }, - { /* ETM 4.0 - A72, Maia, HiSilicon */ - .id = 0x000bb95a, - .mask = 0x000fffff, - .data = "ETM 4.0", - }, - { 0, 0}, + ETM4x_AMBA_ID(0x000bb95d), /* Cortex-A53 */ + ETM4x_AMBA_ID(0x000bb95e), /* Cortex-A57 */ + ETM4x_AMBA_ID(0x000bb95a), /* Cortex-A72 */ + ETM4x_AMBA_ID(0x000bb959), /* Cortex-A73 */ + ETM4x_AMBA_ID(0x000bb9da), /* Cortex-A35 */ + {}, }; static struct amba_driver etm4x_driver = { diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 1820e094280e6aa554dbbf21375c72ba2f0f1f7f..c2fac28ae5ce29241a6b491a513fbf4cb9c6392c 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -573,7 +573,7 @@ static int tmc_etr_alloc_mem(struct tmc_drvdata *drvdata) return ret; } -static void tmc_etr_free_mem(struct tmc_drvdata *drvdata) +void tmc_etr_free_mem(struct tmc_drvdata *drvdata) { if (drvdata->vaddr) { if (drvdata->memtype == TMC_ETR_MEM_TYPE_CONTIG) diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c index 8fef3c073b4fe0c817372319a7ff662c45380603..16c12c4ddd3f4ab1869d7a05acee9953015c745a 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.c +++ b/drivers/hwtracing/coresight/coresight-tmc.c @@ -474,8 +474,12 @@ static ssize_t out_mode_store(struct device *dev, drvdata->out_mode = TMC_ETR_OUT_MODE_USB; spin_unlock_irqrestore(&drvdata->spinlock, flags); - coresight_cti_unmap_trigout(drvdata->cti_flush, 3, 0); - coresight_cti_unmap_trigin(drvdata->cti_reset, 2, 0); + if (drvdata->mode != CS_MODE_DISABLED) { + coresight_cti_unmap_trigin(drvdata->cti_reset, 2, 0); + coresight_cti_unmap_trigout(drvdata->cti_flush, 3, 0); + tmc_etr_byte_cntr_stop(drvdata->byte_cntr); + tmc_etr_free_mem(drvdata); + } drvdata->usbch = usb_qdss_open("qdss", drvdata, usb_notifier); diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index 7fa37cb663bfaca034acdb772c50718ba3f422a6..ba3d376675b7278448f04c1cd4c819ce53d524fe 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -274,6 +274,7 @@ extern struct byte_cntr *byte_cntr_init(struct amba_device *adev, struct tmc_drvdata *drvdata); extern const struct coresight_ops tmc_etr_cs_ops; extern void tmc_etr_sg_rwp_pos(struct tmc_drvdata *drvdata, phys_addr_t rwp); +extern void tmc_etr_free_mem(struct tmc_drvdata *drvdata); extern const struct coresight_ops tmc_etr_cs_ops; diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index 3067e6daca9438717cd31de3d6e5f9e748531a05..91f91bf7bca86ec67267e6d7840f587493076b5f 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -219,6 +219,7 @@ struct dsb_dataset { uint32_t trig_patt_val[TPDM_DSB_MAX_PATT]; uint32_t trig_patt_mask[TPDM_DSB_MAX_PATT]; bool trig_ts; + bool trig_type; uint32_t select_val[TPDM_DSB_MAX_SELECT]; uint32_t msr[TPDM_DSB_MAX_MSR]; }; @@ -271,6 +272,8 @@ struct tpdm_drvdata { bool msr_fix_req; }; +static void tpdm_init_default_data(struct tpdm_drvdata *drvdata); + static void tpdm_setup_disable(struct tpdm_drvdata *drvdata) { int i; @@ -552,6 +555,13 @@ static void __tpdm_enable_dsb(struct tpdm_drvdata *drvdata) val = val | BIT(1); else val = val & ~BIT(1); + + /* Set trigger type */ + if (drvdata->dsb->trig_type) + val = val | BIT(12); + else + val = val & ~BIT(12); + tpdm_writel(drvdata, val, TPDM_DSB_CR); val = tpdm_readl(drvdata, TPDM_DSB_CR); @@ -889,6 +899,57 @@ static ssize_t tpdm_store_enable_datasets(struct device *dev, static DEVICE_ATTR(enable_datasets, 0644, tpdm_show_enable_datasets, tpdm_store_enable_datasets); +static ssize_t reset_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + int ret = 0; + unsigned long val; + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + mutex_lock(&drvdata->lock); + /* Reset all datasets to ZERO */ + if (drvdata->gpr != NULL) + memset(drvdata->gpr, 0, sizeof(struct gpr_dataset)); + + if (drvdata->bc != NULL) + memset(drvdata->bc, 0, sizeof(struct bc_dataset)); + + if (drvdata->dsb != NULL) + memset(drvdata->dsb, 0, sizeof(struct dsb_dataset)); + + if (drvdata->cmb != NULL) { + if (drvdata->cmb->mcmb != NULL) + memset(drvdata->cmb->mcmb, 0, + sizeof(struct mcmb_dataset)); + + memset(drvdata->cmb, 0, sizeof(struct cmb_dataset)); + } + /* Init the default data */ + tpdm_init_default_data(drvdata); + + /* Disable tpdm if enabled */ + if (drvdata->enable) { + __tpdm_disable(drvdata); + drvdata->enable = false; + } + + mutex_unlock(&drvdata->lock); + + if (drvdata->enable) { + tpdm_setup_disable(drvdata); + dev_info(drvdata->dev, "TPDM tracing disabled\n"); + } + + return size; +} +static DEVICE_ATTR_WO(reset); + static ssize_t tpdm_show_gp_regs(struct device *dev, struct device_attribute *attr, char *buf) @@ -3305,6 +3366,43 @@ static ssize_t tpdm_store_dsb_trig_patt_mask(struct device *dev, static DEVICE_ATTR(dsb_trig_patt_mask, 0644, tpdm_show_dsb_trig_patt_mask, tpdm_store_dsb_trig_patt_mask); +static ssize_t tpdm_show_dsb_trig_type(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + + if (!test_bit(TPDM_DS_DSB, drvdata->datasets)) + return -EPERM; + + return scnprintf(buf, PAGE_SIZE, "%u\n", + (unsigned int)drvdata->dsb->trig_type); +} + +static ssize_t tpdm_store_dsb_trig_type(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t size) +{ + struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent); + unsigned long val; + + if (kstrtoul(buf, 16, &val)) + return -EINVAL; + if (!test_bit(TPDM_DS_DSB, drvdata->datasets)) + return -EPERM; + + mutex_lock(&drvdata->lock); + if (val) + drvdata->dsb->trig_type = true; + else + drvdata->dsb->trig_type = false; + mutex_unlock(&drvdata->lock); + return size; +} +static DEVICE_ATTR(dsb_trig_type, 0644, + tpdm_show_dsb_trig_type, tpdm_store_dsb_trig_type); + static ssize_t tpdm_show_dsb_trig_ts(struct device *dev, struct device_attribute *attr, char *buf) @@ -4118,6 +4216,7 @@ static struct attribute *tpdm_dsb_attrs[] = { &dev_attr_dsb_trig_patt_val.attr, &dev_attr_dsb_trig_patt_mask.attr, &dev_attr_dsb_trig_ts.attr, + &dev_attr_dsb_trig_type.attr, &dev_attr_dsb_select_val.attr, &dev_attr_dsb_msr.attr, NULL, @@ -4162,6 +4261,7 @@ static struct attribute_group tpdm_cmb_attr_grp = { static struct attribute *tpdm_attrs[] = { &dev_attr_available_datasets.attr, &dev_attr_enable_datasets.attr, + &dev_attr_reset.attr, &dev_attr_gp_regs.attr, NULL, }; @@ -4231,8 +4331,10 @@ static void tpdm_init_default_data(struct tpdm_drvdata *drvdata) if (test_bit(TPDM_DS_TC, drvdata->datasets)) drvdata->tc->retrieval_mode = TPDM_MODE_ATB; - if (test_bit(TPDM_DS_DSB, drvdata->datasets)) + if (test_bit(TPDM_DS_DSB, drvdata->datasets)) { drvdata->dsb->trig_ts = true; + drvdata->dsb->trig_type = false; + } if (test_bit(TPDM_DS_CMB, drvdata->datasets) || test_bit(TPDM_DS_MCMB, drvdata->datasets)) diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index 735dca089389ac7904bf533317d8ab8c8a4ed060..15dd01f8c197657bec42a61b909ba84a22df3deb 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c @@ -47,8 +47,9 @@ /** register definition **/ /* FFSR - 0x300 */ -#define FFSR_FT_STOPPED BIT(1) +#define FFSR_FT_STOPPED_BIT 1 /* FFCR - 0x304 */ +#define FFCR_FON_MAN_BIT 6 #define FFCR_FON_MAN BIT(6) #define FFCR_STOP_FI BIT(12) @@ -93,9 +94,9 @@ static void tpiu_disable_hw(struct tpiu_drvdata *drvdata) /* Generate manual flush */ writel_relaxed(FFCR_STOP_FI | FFCR_FON_MAN, drvdata->base + TPIU_FFCR); /* Wait for flush to complete */ - coresight_timeout(drvdata->base, TPIU_FFCR, FFCR_FON_MAN, 0); + coresight_timeout(drvdata->base, TPIU_FFCR, FFCR_FON_MAN_BIT, 0); /* Wait for formatter to stop */ - coresight_timeout(drvdata->base, TPIU_FFSR, FFSR_FT_STOPPED, 1); + coresight_timeout(drvdata->base, TPIU_FFSR, FFSR_FT_STOPPED_BIT, 1); CS_LOCK(drvdata->base); } diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 7bb1ed6936423b7653f5d22ac508445da5c863bd..3a66a54d572e9ea3f6e5d36d4e396b41a939fbff 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -131,7 +131,7 @@ static int coresight_find_link_inport(struct coresight_device *csdev, dev_err(&csdev->dev, "couldn't find inport, parent: %s, child: %s\n", dev_name(&parent->dev), dev_name(&csdev->dev)); - return 0; + return -ENODEV; } static int coresight_find_link_outport(struct coresight_device *csdev, @@ -149,7 +149,7 @@ static int coresight_find_link_outport(struct coresight_device *csdev, dev_err(&csdev->dev, "couldn't find outport, parent: %s, child: %s\n", dev_name(&csdev->dev), dev_name(&child->dev)); - return 0; + return -ENODEV; } static int coresight_enable_sink(struct coresight_device *csdev, u32 mode) @@ -203,6 +203,9 @@ static int coresight_enable_link(struct coresight_device *csdev, else refport = 0; + if (refport < 0) + return refport; + if (atomic_inc_return(&csdev->refcnt[refport]) == 1) { if (link_ops(csdev)->enable) { ret = link_ops(csdev)->enable(csdev, inport, outport); diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c index c1793313bb0873fea10e263062f6e580d34c7670..757801d2760439ac116acc52a0995af618331125 100644 --- a/drivers/hwtracing/intel_th/core.c +++ b/drivers/hwtracing/intel_th/core.c @@ -147,7 +147,8 @@ static int intel_th_remove(struct device *dev) th->thdev[i] = NULL; } - th->num_thdevs = lowest; + if (lowest >= 0) + th->num_thdevs = lowest; } if (thdrv->attr_group) diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c index 284f8670dbeb748bd8d0c6f240bbf41e62ce95f7..a074735456bc7571eab7e153168cd913ce9e4651 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c @@ -110,22 +110,22 @@ #define ASPEED_I2CD_DEV_ADDR_MASK GENMASK(6, 0) enum aspeed_i2c_master_state { + ASPEED_I2C_MASTER_INACTIVE, ASPEED_I2C_MASTER_START, ASPEED_I2C_MASTER_TX_FIRST, ASPEED_I2C_MASTER_TX, ASPEED_I2C_MASTER_RX_FIRST, ASPEED_I2C_MASTER_RX, ASPEED_I2C_MASTER_STOP, - ASPEED_I2C_MASTER_INACTIVE, }; enum aspeed_i2c_slave_state { + ASPEED_I2C_SLAVE_STOP, ASPEED_I2C_SLAVE_START, ASPEED_I2C_SLAVE_READ_REQUESTED, ASPEED_I2C_SLAVE_READ_PROCESSED, ASPEED_I2C_SLAVE_WRITE_REQUESTED, ASPEED_I2C_SLAVE_WRITE_RECEIVED, - ASPEED_I2C_SLAVE_STOP, }; struct aspeed_i2c_bus { @@ -859,7 +859,7 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) if (!match) bus->get_clk_reg_val = aspeed_i2c_24xx_get_clk_reg_val; else - bus->get_clk_reg_val = match->data; + bus->get_clk_reg_val = (u32 (*)(u32))match->data; /* Initialize the I2C adapter */ spin_lock_init(&bus->lock); diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index b8c43535f16cf29b8f8b517fe2e7ecaba1c80156..5cf670f57be71c3f81b7ebc57f7a0aec325e5ce6 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -234,12 +234,16 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev) /* * It's not always possible to have 1 to 2 ratio when d=7, so fall back * to minimal possible clkh in this case. + * + * Note: + * CLKH is not allowed to be 0, in this case I2C clock is not generated + * at all */ - if (clk >= clkl + d) { + if (clk > clkl + d) { clkh = clk - clkl - d; clkl -= d; } else { - clkh = 0; + clkh = 1; clkl = clk - (d << 1); } diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index ba8df2fde1b2769fe65bdf49f338625577b6ced9..06debfa903b9c582f25fdc13fe7a0a359c055630 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -138,6 +138,7 @@ #define SBREG_BAR 0x10 #define SBREG_SMBCTRL 0xc6000c +#define SBREG_SMBCTRL_DNV 0xcf000c /* Host status bits for SMBPCISTS */ #define SMBPCISTS_INTS BIT(3) @@ -1395,7 +1396,11 @@ static void i801_add_tco(struct i801_priv *priv) spin_unlock(&p2sb_spinlock); res = &tco_res[ICH_RES_MEM_OFF]; - res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL; + if (pci_dev->device == PCI_DEVICE_ID_INTEL_DNV_SMBUS) + res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL_DNV; + else + res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL; + res->end = res->start + 3; res->flags = IORESOURCE_MEM; @@ -1411,6 +1416,13 @@ static void i801_add_tco(struct i801_priv *priv) } #ifdef CONFIG_ACPI +static bool i801_acpi_is_smbus_ioport(const struct i801_priv *priv, + acpi_physical_address address) +{ + return address >= priv->smba && + address <= pci_resource_end(priv->pci_dev, SMBBAR); +} + static acpi_status i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits, u64 *value, void *handler_context, void *region_context) @@ -1426,7 +1438,7 @@ i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits, */ mutex_lock(&priv->acpi_lock); - if (!priv->acpi_reserved) { + if (!priv->acpi_reserved && i801_acpi_is_smbus_ioport(priv, address)) { priv->acpi_reserved = true; dev_warn(&pdev->dev, "BIOS is accessing SMBus registers\n"); diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 75c6b98585ba2e545ac0b3239e237796b68881b7..b73dd837fb533ae06491074b2a17a2a37d0db66f 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -665,9 +665,6 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx, struct imx_i2c_dma *dma = i2c_imx->dma; struct device *dev = &i2c_imx->adapter.dev; - temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); - temp |= I2CR_DMAEN; - imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); dma->chan_using = dma->chan_rx; dma->dma_transfer_dir = DMA_DEV_TO_MEM; @@ -780,6 +777,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo int i, result; unsigned int temp; int block_data = msgs->flags & I2C_M_RECV_LEN; + int use_dma = i2c_imx->dma && msgs->len >= DMA_THRESHOLD && !block_data; dev_dbg(&i2c_imx->adapter.dev, "<%s> write slave address: addr=0x%x\n", @@ -806,12 +804,14 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo */ if ((msgs->len - 1) || block_data) temp &= ~I2CR_TXAK; + if (use_dma) + temp |= I2CR_DMAEN; imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */ dev_dbg(&i2c_imx->adapter.dev, "<%s> read data\n", __func__); - if (i2c_imx->dma && msgs->len >= DMA_THRESHOLD && !block_data) + if (use_dma) return i2c_imx_dma_read(i2c_imx, msgs, is_lastmsg); /* read data */ diff --git a/drivers/i2c/busses/i2c-uniphier-f.c b/drivers/i2c/busses/i2c-uniphier-f.c index 9918bdd816196281ae6c64d364d34ecaf89a65ef..a403e8579b652b6e2486f746b91b9357c3ab7381 100644 --- a/drivers/i2c/busses/i2c-uniphier-f.c +++ b/drivers/i2c/busses/i2c-uniphier-f.c @@ -401,11 +401,8 @@ static int uniphier_fi2c_master_xfer(struct i2c_adapter *adap, return ret; for (msg = msgs; msg < emsg; msg++) { - /* If next message is read, skip the stop condition */ - bool stop = !(msg + 1 < emsg && msg[1].flags & I2C_M_RD); - /* but, force it if I2C_M_STOP is set */ - if (msg->flags & I2C_M_STOP) - stop = true; + /* Emit STOP if it is the last message or I2C_M_STOP is set. */ + bool stop = (msg + 1 == emsg) || (msg->flags & I2C_M_STOP); ret = uniphier_fi2c_master_xfer_one(adap, msg, stop); if (ret) diff --git a/drivers/i2c/busses/i2c-uniphier.c b/drivers/i2c/busses/i2c-uniphier.c index bb181b0882919acef145d27ec236b705b8f2e7f0..454f914ae66dbd49931575122bb7c7dea662b11b 100644 --- a/drivers/i2c/busses/i2c-uniphier.c +++ b/drivers/i2c/busses/i2c-uniphier.c @@ -248,11 +248,8 @@ static int uniphier_i2c_master_xfer(struct i2c_adapter *adap, return ret; for (msg = msgs; msg < emsg; msg++) { - /* If next message is read, skip the stop condition */ - bool stop = !(msg + 1 < emsg && msg[1].flags & I2C_M_RD); - /* but, force it if I2C_M_STOP is set */ - if (msg->flags & I2C_M_STOP) - stop = true; + /* Emit STOP if it is the last message or I2C_M_STOP is set. */ + bool stop = (msg + 1 == emsg) || (msg->flags & I2C_M_STOP); ret = uniphier_i2c_master_xfer_one(adap, msg, stop); if (ret) diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index ae6ed254e01db5c10eb79e7bed4718da4d94536a..732d6c456a6f1cdb9e9687125930bd6722216ef0 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -538,6 +538,7 @@ static void xiic_start_recv(struct xiic_i2c *i2c) { u8 rx_watermark; struct i2c_msg *msg = i2c->rx_msg = i2c->tx_msg; + unsigned long flags; /* Clear and enable Rx full interrupt. */ xiic_irq_clr_en(i2c, XIIC_INTR_RX_FULL_MASK | XIIC_INTR_TX_ERROR_MASK); @@ -553,6 +554,7 @@ static void xiic_start_recv(struct xiic_i2c *i2c) rx_watermark = IIC_RX_FIFO_DEPTH; xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, rx_watermark - 1); + local_irq_save(flags); if (!(msg->flags & I2C_M_NOSTART)) /* write the address */ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, @@ -563,6 +565,8 @@ static void xiic_start_recv(struct xiic_i2c *i2c) xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, msg->len | ((i2c->nmsgs == 1) ? XIIC_TX_DYN_STOP_MASK : 0)); + local_irq_restore(flags); + if (i2c->nmsgs == 1) /* very last, enable bus not busy as well */ xiic_irq_clr_en(i2c, XIIC_INTR_BNB_MASK); diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c index a9126b3cda61bc95f6a9d1282821ab7552484534..847d9bf6744c21bde84d1c04aec88ad64a059a68 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -475,11 +475,16 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, msgs[0].buf = buffer; ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); - if (ret < 0) - dev_err(&client->adapter->dev, "i2c write failed\n"); kfree(buffer); - return ret; + + if (ret < 0) { + dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret); + return ret; + } + + /* 1 transfer must have completed successfully */ + return (ret == 1) ? 0 : -EIO; } static acpi_status diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 6f2fe63e8f5aa80ade4daa76bdfe0b48516b2256..7b961c9c62eff5175bfdb193f215f1a78be8b83c 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -638,7 +638,7 @@ static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr) static void i2c_adapter_lock_bus(struct i2c_adapter *adapter, unsigned int flags) { - rt_mutex_lock(&adapter->bus_lock); + rt_mutex_lock_nested(&adapter->bus_lock, i2c_adapter_depth(adapter)); } /** diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c index 9669ca4937b891063d4cd63e552344d818f5eefa..7ba31f6bf1488e5a3ffef565d0d7c85091c91f0c 100644 --- a/drivers/i2c/i2c-mux.c +++ b/drivers/i2c/i2c-mux.c @@ -144,7 +144,7 @@ static void i2c_mux_lock_bus(struct i2c_adapter *adapter, unsigned int flags) struct i2c_mux_priv *priv = adapter->algo_data; struct i2c_adapter *parent = priv->muxc->parent; - rt_mutex_lock(&parent->mux_lock); + rt_mutex_lock_nested(&parent->mux_lock, i2c_adapter_depth(adapter)); if (!(flags & I2C_LOCK_ROOT_ADAPTER)) return; i2c_lock_bus(parent, flags); @@ -181,7 +181,7 @@ static void i2c_parent_lock_bus(struct i2c_adapter *adapter, struct i2c_mux_priv *priv = adapter->algo_data; struct i2c_adapter *parent = priv->muxc->parent; - rt_mutex_lock(&parent->mux_lock); + rt_mutex_lock_nested(&parent->mux_lock, i2c_adapter_depth(adapter)); i2c_lock_bus(parent, flags); } diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c index 9ccb5828db986def7c1531b5196457995b909190..3dda7afe8a11632bbdec2d12d17eb131198aaa0e 100644 --- a/drivers/iio/accel/adxl345_core.c +++ b/drivers/iio/accel/adxl345_core.c @@ -21,6 +21,8 @@ #define ADXL345_REG_DATAX0 0x32 #define ADXL345_REG_DATAY0 0x34 #define ADXL345_REG_DATAZ0 0x36 +#define ADXL345_REG_DATA_AXIS(index) \ + (ADXL345_REG_DATAX0 + (index) * sizeof(__le16)) #define ADXL345_POWER_CTL_MEASURE BIT(3) #define ADXL345_POWER_CTL_STANDBY 0x00 @@ -47,19 +49,19 @@ struct adxl345_data { u8 data_range; }; -#define ADXL345_CHANNEL(reg, axis) { \ +#define ADXL345_CHANNEL(index, axis) { \ .type = IIO_ACCEL, \ .modified = 1, \ .channel2 = IIO_MOD_##axis, \ - .address = reg, \ + .address = index, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ } static const struct iio_chan_spec adxl345_channels[] = { - ADXL345_CHANNEL(ADXL345_REG_DATAX0, X), - ADXL345_CHANNEL(ADXL345_REG_DATAY0, Y), - ADXL345_CHANNEL(ADXL345_REG_DATAZ0, Z), + ADXL345_CHANNEL(0, X), + ADXL345_CHANNEL(1, Y), + ADXL345_CHANNEL(2, Z), }; static int adxl345_read_raw(struct iio_dev *indio_dev, @@ -67,7 +69,7 @@ static int adxl345_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct adxl345_data *data = iio_priv(indio_dev); - __le16 regval; + __le16 accel; int ret; switch (mask) { @@ -77,12 +79,13 @@ static int adxl345_read_raw(struct iio_dev *indio_dev, * ADXL345_REG_DATA(X0/Y0/Z0) contain the least significant byte * and ADXL345_REG_DATA(X0/Y0/Z0) + 1 the most significant byte */ - ret = regmap_bulk_read(data->regmap, chan->address, ®val, - sizeof(regval)); + ret = regmap_bulk_read(data->regmap, + ADXL345_REG_DATA_AXIS(chan->address), + &accel, sizeof(accel)); if (ret < 0) return ret; - *val = sign_extend32(le16_to_cpu(regval), 12); + *val = sign_extend32(le16_to_cpu(accel), 12); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = 0; diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c index 565f7d8d3304a3eba3b13d69ad568cc7f916b9bd..f2761b3855411d6db48ef93291c7d4ac256ac93f 100644 --- a/drivers/iio/accel/sca3000.c +++ b/drivers/iio/accel/sca3000.c @@ -797,6 +797,7 @@ static int sca3000_write_raw(struct iio_dev *indio_dev, mutex_lock(&st->lock); ret = sca3000_write_3db_freq(st, val); mutex_unlock(&st->lock); + return ret; default: return -EINVAL; } diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index 59f99b3a180d7332c4bc41f45d14bdbc12ada06c..d5b9f831eba77e0ce32db8f812cee197df7b44a7 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -701,6 +702,7 @@ static int ina2xx_buffer_enable(struct iio_dev *indio_dev) { struct ina2xx_chip_info *chip = iio_priv(indio_dev); unsigned int sampling_us = SAMPLING_PERIOD(chip); + struct task_struct *task; dev_dbg(&indio_dev->dev, "Enabling buffer w/ scan_mask %02x, freq = %d, avg =%u\n", (unsigned int)(*indio_dev->active_scan_mask), @@ -710,11 +712,17 @@ static int ina2xx_buffer_enable(struct iio_dev *indio_dev) dev_dbg(&indio_dev->dev, "Async readout mode: %d\n", chip->allow_async_readout); - chip->task = kthread_run(ina2xx_capture_thread, (void *)indio_dev, - "%s:%d-%uus", indio_dev->name, indio_dev->id, - sampling_us); + task = kthread_create(ina2xx_capture_thread, (void *)indio_dev, + "%s:%d-%uus", indio_dev->name, indio_dev->id, + sampling_us); + if (IS_ERR(task)) + return PTR_ERR(task); + + get_task_struct(task); + wake_up_process(task); + chip->task = task; - return PTR_ERR_OR_ZERO(chip->task); + return 0; } static int ina2xx_buffer_disable(struct iio_dev *indio_dev) @@ -723,6 +731,7 @@ static int ina2xx_buffer_disable(struct iio_dev *indio_dev) if (chip->task) { kthread_stop(chip->task); + put_task_struct(chip->task); chip->task = NULL; } diff --git a/drivers/iio/counter/104-quad-8.c b/drivers/iio/counter/104-quad-8.c index ba3d9030cd514f6ac433fb8ca7703eb97c71c0ac..181585ae6e171cc40bbe5dc3356335e990cd034c 100644 --- a/drivers/iio/counter/104-quad-8.c +++ b/drivers/iio/counter/104-quad-8.c @@ -138,7 +138,7 @@ static int quad8_write_raw(struct iio_dev *indio_dev, outb(val >> (8 * i), base_offset); /* Reset Borrow, Carry, Compare, and Sign flags */ - outb(0x02, base_offset + 1); + outb(0x04, base_offset + 1); /* Reset Error flag */ outb(0x06, base_offset + 1); diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c index 99eba524f6ddbe063d2cf2ac359491287177d10b..1642b55f70da3ab28fa604c3e373bbab429ac593 100644 --- a/drivers/iio/frequency/ad9523.c +++ b/drivers/iio/frequency/ad9523.c @@ -508,7 +508,7 @@ static ssize_t ad9523_store(struct device *dev, return ret; if (!state) - return 0; + return len; mutex_lock(&indio_dev->mlock); switch ((u32)this_attr->address) { @@ -642,7 +642,7 @@ static int ad9523_read_raw(struct iio_dev *indio_dev, code = (AD9523_CLK_DIST_DIV_PHASE_REV(ret) * 3141592) / AD9523_CLK_DIST_DIV_REV(ret); *val = code / 1000000; - *val2 = (code % 1000000) * 10; + *val2 = code % 1000000; return IIO_VAL_INT_PLUS_MICRO; default: return -EINVAL; diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index 8f26428804a236fa1a38e612c0cd6aa3245b7eff..5f625ffa2a88d8b12d10491d85e920e519c8a97c 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -362,10 +362,9 @@ static int bmp280_read_humid(struct bmp280_data *data, int *val, int *val2) } comp_humidity = bmp280_compensate_humidity(data, adc_humidity); - *val = comp_humidity; - *val2 = 1024; + *val = comp_humidity * 1000 / 1024; - return IIO_VAL_FRACTIONAL; + return IIO_VAL_INT; } static int bmp280_read_raw(struct iio_dev *indio_dev, diff --git a/drivers/iio/temperature/maxim_thermocouple.c b/drivers/iio/temperature/maxim_thermocouple.c index d70e2e53d6a78cc5ab8ee073a7e01e5f635483d1..557214202eff35dd870ea085a81161de2982c147 100644 --- a/drivers/iio/temperature/maxim_thermocouple.c +++ b/drivers/iio/temperature/maxim_thermocouple.c @@ -267,7 +267,6 @@ static int maxim_thermocouple_remove(struct spi_device *spi) static const struct spi_device_id maxim_thermocouple_id[] = { {"max6675", MAX6675}, {"max31855", MAX31855}, - {"max31856", MAX31855}, {}, }; MODULE_DEVICE_TABLE(spi, maxim_thermocouple_id); diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 79843a3ca9dcd53d8cc4362bb72b9124ed33bd65..7c5eca312aa884d8a3a11a3651a361d6af12f3ea 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -730,6 +730,7 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv) dgid = (union ib_gid *) &addr->sib_addr; pkey = ntohs(addr->sib_pkey); + mutex_lock(&lock); list_for_each_entry(cur_dev, &dev_list, list) { for (p = 1; p <= cur_dev->device->phys_port_cnt; ++p) { if (!rdma_cap_af_ib(cur_dev->device, p)) @@ -756,18 +757,19 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv) cma_dev = cur_dev; sgid = gid; id_priv->id.port_num = p; + goto found; } } } } - - if (!cma_dev) - return -ENODEV; + mutex_unlock(&lock); + return -ENODEV; found: cma_attach_to_dev(id_priv, cma_dev); - addr = (struct sockaddr_ib *) cma_src_addr(id_priv); - memcpy(&addr->sib_addr, &sgid, sizeof sgid); + mutex_unlock(&lock); + addr = (struct sockaddr_ib *)cma_src_addr(id_priv); + memcpy(&addr->sib_addr, &sgid, sizeof(sgid)); cma_translate_ib(addr, &id_priv->id.route.addr.dev_addr); return 0; } @@ -1459,9 +1461,16 @@ static bool cma_match_net_dev(const struct rdma_cm_id *id, (addr->src_addr.ss_family == AF_IB || cma_protocol_roce_dev_port(id->device, port_num)); - return !addr->dev_addr.bound_dev_if || - (net_eq(dev_net(net_dev), addr->dev_addr.net) && - addr->dev_addr.bound_dev_if == net_dev->ifindex); + /* + * Net namespaces must match, and if the listner is listening + * on a specific netdevice than netdevice must match as well. + */ + if (net_eq(dev_net(net_dev), addr->dev_addr.net) && + (!!addr->dev_addr.bound_dev_if == + (addr->dev_addr.bound_dev_if == net_dev->ifindex))) + return true; + else + return false; } static struct rdma_id_private *cma_find_listener( diff --git a/drivers/infiniband/core/rw.c b/drivers/infiniband/core/rw.c index 6ca607e8e293cab4405f6da09af5df8c0b7710ff..9939dcfb1b6a5b434879c3a168c5273aec142f22 100644 --- a/drivers/infiniband/core/rw.c +++ b/drivers/infiniband/core/rw.c @@ -87,7 +87,7 @@ static int rdma_rw_init_one_mr(struct ib_qp *qp, u8 port_num, } ret = ib_map_mr_sg(reg->mr, sg, nents, &offset, PAGE_SIZE); - if (ret < nents) { + if (ret < 0 || ret < nents) { ib_mr_pool_put(qp, &qp->rdma_mrs, reg->mr); return -EINVAL; } diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index a22b992cde38c2bdf586bcea56b2edb351b8bf89..17144a781aebc5c504a31efeae121be1fb5c283c 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -124,6 +124,8 @@ static DEFINE_MUTEX(mut); static DEFINE_IDR(ctx_idr); static DEFINE_IDR(multicast_idr); +static const struct file_operations ucma_fops; + static inline struct ucma_context *_ucma_find_context(int id, struct ucma_file *file) { @@ -1564,6 +1566,10 @@ static ssize_t ucma_migrate_id(struct ucma_file *new_file, f = fdget(cmd.fd); if (!f.file) return -ENOENT; + if (f.file->f_op != &ucma_fops) { + ret = -EINVAL; + goto file_put; + } /* Validate current fd and prevent destruction of id. */ ctx = ucma_get_ctx(f.file->private_data, cmd.id); @@ -1736,6 +1742,8 @@ static int ucma_close(struct inode *inode, struct file *filp) mutex_lock(&mut); if (!ctx->closing) { mutex_unlock(&mut); + ucma_put_ctx(ctx); + wait_for_completion(&ctx->comp); /* rdma_destroy_id ensures that no event handlers are * inflight for that id before releasing it. */ diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 0f70ff91276ef658db38d2cb856402c4336b4a6f..aff6ef3ad52c2f3648dbf5356ef9b7a5b94915fa 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -424,6 +424,7 @@ static int ib_uverbs_comp_event_close(struct inode *inode, struct file *filp) list_del(&entry->obj_list); kfree(entry); } + file->ev_queue.is_closed = 1; spin_unlock_irq(&file->ev_queue.lock); uverbs_close_fd(filp); diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.c b/drivers/infiniband/hw/bnxt_re/qplib_sp.c index 9536de8c5fb8b3d977b78a43af180b6d4b035b8d..124c8915b9eeee88f599b129e2760f2c767281e6 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_sp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.c @@ -156,7 +156,7 @@ int bnxt_qplib_get_sgid(struct bnxt_qplib_res *res, struct bnxt_qplib_sgid_tbl *sgid_tbl, int index, struct bnxt_qplib_gid *gid) { - if (index > sgid_tbl->max) { + if (index >= sgid_tbl->max) { dev_err(&res->pdev->dev, "QPLIB: Index %d exceeded SGID table max (%d)", index, sgid_tbl->max); @@ -361,7 +361,7 @@ int bnxt_qplib_get_pkey(struct bnxt_qplib_res *res, *pkey = 0xFFFF; return 0; } - if (index > pkey_tbl->max) { + if (index >= pkey_tbl->max) { dev_err(&res->pdev->dev, "QPLIB: Index %d exceeded PKEY table max (%d)", index, pkey_tbl->max); diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index a8a8f65a1e51bd5e3868951fd801beca9e0e5d1a..24952af51a546bc325adb095d713d435a1d422f7 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -1395,6 +1395,12 @@ static void flush_qp(struct c4iw_qp *qhp) schp = to_c4iw_cq(qhp->ibqp.send_cq); if (qhp->ibqp.uobject) { + + /* for user qps, qhp->wq.flushed is protected by qhp->mutex */ + if (qhp->wq.flushed) + return; + + qhp->wq.flushed = 1; t4_set_wq_in_error(&qhp->wq); t4_set_cq_in_error(&rchp->cq); spin_lock_irqsave(&rchp->comp_handler_lock, flag); diff --git a/drivers/infiniband/hw/hfi1/affinity.c b/drivers/infiniband/hw/hfi1/affinity.c index b5fab55cc275068166369c184a759ab9a925849d..b197e925fe3639dfc33b4ce373876ee0a50f152a 100644 --- a/drivers/infiniband/hw/hfi1/affinity.c +++ b/drivers/infiniband/hw/hfi1/affinity.c @@ -146,7 +146,7 @@ int node_affinity_init(void) while ((dev = pci_get_device(ids->vendor, ids->device, dev))) { node = pcibus_to_node(dev->bus); if (node < 0) - node = numa_node_id(); + goto out; hfi1_per_node_cntr[node]++; } @@ -154,6 +154,18 @@ int node_affinity_init(void) } return 0; + +out: + /* + * Invalid PCI NUMA node information found, note it, and populate + * our database 1:1. + */ + pr_err("HFI: Invalid PCI NUMA node. Performance may be affected\n"); + pr_err("HFI: System BIOS may need to be upgraded\n"); + for (node = 0; node < node_affinity.num_possible_nodes; node++) + hfi1_per_node_cntr[node] = 1; + + return 0; } void node_affinity_destroy(void) @@ -227,8 +239,14 @@ int hfi1_dev_affinity_init(struct hfi1_devdata *dd) const struct cpumask *local_mask; int curr_cpu, possible, i; - if (node < 0) - node = numa_node_id(); + /* + * If the BIOS does not have the NUMA node information set, select + * NUMA 0 so we get consistent performance. + */ + if (node < 0) { + dd_dev_err(dd, "Invalid PCI NUMA node. Performance may be affected\n"); + node = 0; + } dd->node = node; local_mask = cpumask_of_node(dd->node); diff --git a/drivers/infiniband/hw/hfi1/pio.c b/drivers/infiniband/hw/hfi1/pio.c index a95ac62465592080ea60a2db31416e2b7b335288..19a8e6052820fec0344f3b81700017a49f21ab01 100644 --- a/drivers/infiniband/hw/hfi1/pio.c +++ b/drivers/infiniband/hw/hfi1/pio.c @@ -86,6 +86,7 @@ void pio_send_control(struct hfi1_devdata *dd, int op) unsigned long flags; int write = 1; /* write sendctrl back */ int flush = 0; /* re-read sendctrl to make sure it is flushed */ + int i; spin_lock_irqsave(&dd->sendctrl_lock, flags); @@ -95,9 +96,13 @@ void pio_send_control(struct hfi1_devdata *dd, int op) reg |= SEND_CTRL_SEND_ENABLE_SMASK; /* Fall through */ case PSC_DATA_VL_ENABLE: + mask = 0; + for (i = 0; i < ARRAY_SIZE(dd->vld); i++) + if (!dd->vld[i].mtu) + mask |= BIT_ULL(i); /* Disallow sending on VLs not enabled */ - mask = (((~0ull) << num_vls) & SEND_CTRL_UNSUPPORTED_VL_MASK) << - SEND_CTRL_UNSUPPORTED_VL_SHIFT; + mask = (mask & SEND_CTRL_UNSUPPORTED_VL_MASK) << + SEND_CTRL_UNSUPPORTED_VL_SHIFT; reg = (reg & ~SEND_CTRL_UNSUPPORTED_VL_SMASK) | mask; break; case PSC_GLOBAL_DISABLE: diff --git a/drivers/infiniband/hw/hfi1/user_sdma.c b/drivers/infiniband/hw/hfi1/user_sdma.c index c0c0e0445cbfbd72938fe07520f574515992298b..8c954a0ae3b69d9e0834f6906b2ba68f0acdeba0 100644 --- a/drivers/infiniband/hw/hfi1/user_sdma.c +++ b/drivers/infiniband/hw/hfi1/user_sdma.c @@ -828,7 +828,7 @@ static int user_sdma_send_pkts(struct user_sdma_request *req, unsigned maxpkts) if (ACCESS_ONCE(iovec->offset) == iovec->iov.iov_len) { if (++req->iov_idx == req->data_iovs) { ret = -EFAULT; - goto free_txreq; + goto free_tx; } iovec = &req->iovs[req->iov_idx]; WARN_ON(iovec->offset); diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c index e232f3c608b41795a2da43b5439687756c9ec24d..63d404a6752a19db474303f31205e2b2e087d38e 100644 --- a/drivers/infiniband/hw/hfi1/verbs.c +++ b/drivers/infiniband/hw/hfi1/verbs.c @@ -1573,6 +1573,7 @@ static int hfi1_check_ah(struct ib_device *ibdev, struct rdma_ah_attr *ah_attr) struct hfi1_pportdata *ppd; struct hfi1_devdata *dd; u8 sc5; + u8 sl; if (hfi1_check_mcast(rdma_ah_get_dlid(ah_attr)) && !(rdma_ah_get_ah_flags(ah_attr) & IB_AH_GRH)) @@ -1581,8 +1582,13 @@ static int hfi1_check_ah(struct ib_device *ibdev, struct rdma_ah_attr *ah_attr) /* test the mapping for validity */ ibp = to_iport(ibdev, rdma_ah_get_port_num(ah_attr)); ppd = ppd_from_ibp(ibp); - sc5 = ibp->sl_to_sc[rdma_ah_get_sl(ah_attr)]; dd = dd_from_ppd(ppd); + + sl = rdma_ah_get_sl(ah_attr); + if (sl >= ARRAY_SIZE(ibp->sl_to_sc)) + return -EINVAL; + + sc5 = ibp->sl_to_sc[sl]; if (sc_to_vlt(dd, sc5) > num_vls && sc_to_vlt(dd, sc5) != 0xf) return -EINVAL; return 0; diff --git a/drivers/infiniband/hw/hns/hns_roce_pd.c b/drivers/infiniband/hw/hns/hns_roce_pd.c index a64500fa114531e769b7816d1e5304559642d45b..3cef53c651331ffc2325b5868106c3b91b7b1358 100644 --- a/drivers/infiniband/hw/hns/hns_roce_pd.c +++ b/drivers/infiniband/hw/hns/hns_roce_pd.c @@ -35,7 +35,7 @@ static int hns_roce_pd_alloc(struct hns_roce_dev *hr_dev, unsigned long *pdn) { - return hns_roce_bitmap_alloc(&hr_dev->pd_bitmap, pdn); + return hns_roce_bitmap_alloc(&hr_dev->pd_bitmap, pdn) ? -ENOMEM : 0; } static void hns_roce_pd_free(struct hns_roce_dev *hr_dev, unsigned long pdn) diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c index f5dd21c2d275eb6eb0db9cfe335f230cc9e33874..3a37d26889df169a61cd785cb455fb47d3863019 100644 --- a/drivers/infiniband/hw/hns/hns_roce_qp.c +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c @@ -114,7 +114,10 @@ static int hns_roce_reserve_range_qp(struct hns_roce_dev *hr_dev, int cnt, { struct hns_roce_qp_table *qp_table = &hr_dev->qp_table; - return hns_roce_bitmap_alloc_range(&qp_table->bitmap, cnt, align, base); + return hns_roce_bitmap_alloc_range(&qp_table->bitmap, cnt, align, + base) ? + -ENOMEM : + 0; } enum hns_roce_qp_state to_hns_roce_state(enum ib_qp_state state) diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c index b7961f21b555b5a348c520aa184edfe00dacd116..39398dd074d662778066b4deb7d10aac22c174dd 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c @@ -1408,6 +1408,7 @@ static void i40iw_set_hugetlb_values(u64 addr, struct i40iw_mr *iwmr) struct vm_area_struct *vma; struct hstate *h; + down_read(¤t->mm->mmap_sem); vma = find_vma(current->mm, addr); if (vma && is_vm_hugetlb_page(vma)) { h = hstate_vma(vma); @@ -1416,6 +1417,7 @@ static void i40iw_set_hugetlb_values(u64 addr, struct i40iw_mr *iwmr) iwmr->page_msk = huge_page_mask(h); } } + up_read(¤t->mm->mmap_sem); } /** diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c index 1587cedee13e2df7a1515700d6eaabdce862bccc..761d3ce6a63a0a2cc31e8ed5787dc35c13881d58 100644 --- a/drivers/infiniband/hw/mlx4/mr.c +++ b/drivers/infiniband/hw/mlx4/mr.c @@ -247,8 +247,11 @@ int mlx4_ib_rereg_user_mr(struct ib_mr *mr, int flags, } if (flags & IB_MR_REREG_ACCESS) { - if (ib_access_writable(mr_access_flags) && !mmr->umem->writable) - return -EPERM; + if (ib_access_writable(mr_access_flags) && + !mmr->umem->writable) { + err = -EPERM; + goto release_mpt_entry; + } err = mlx4_mr_hw_change_access(dev->dev, *pmpt_entry, convert_access(mr_access_flags)); diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index 9354fec8efe78321c6d909d54d6d843933f003d3..e10c3d915e389156fb26debfbd33cbec7c6cd86b 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -4014,9 +4014,9 @@ static void to_rdma_ah_attr(struct mlx4_ib_dev *ibdev, u8 port_num = path->sched_queue & 0x40 ? 2 : 1; memset(ah_attr, 0, sizeof(*ah_attr)); - ah_attr->type = rdma_ah_find_type(&ibdev->ib_dev, port_num); if (port_num == 0 || port_num > dev->caps.num_ports) return; + ah_attr->type = rdma_ah_find_type(&ibdev->ib_dev, port_num); if (ah_attr->type == RDMA_AH_ATTR_TYPE_ROCE) rdma_ah_set_sl(ah_attr, ((path->sched_queue >> 3) & 0x7) | diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c index 3c7522d025f2b559f638fd2bde05200702488dde..93d67d97c279441f939705bb83298c3612563662 100644 --- a/drivers/infiniband/hw/mlx5/srq.c +++ b/drivers/infiniband/hw/mlx5/srq.c @@ -266,18 +266,24 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd, desc_size = sizeof(struct mlx5_wqe_srq_next_seg) + srq->msrq.max_gs * sizeof(struct mlx5_wqe_data_seg); - if (desc_size == 0 || srq->msrq.max_gs > desc_size) - return ERR_PTR(-EINVAL); + if (desc_size == 0 || srq->msrq.max_gs > desc_size) { + err = -EINVAL; + goto err_srq; + } desc_size = roundup_pow_of_two(desc_size); desc_size = max_t(size_t, 32, desc_size); - if (desc_size < sizeof(struct mlx5_wqe_srq_next_seg)) - return ERR_PTR(-EINVAL); + if (desc_size < sizeof(struct mlx5_wqe_srq_next_seg)) { + err = -EINVAL; + goto err_srq; + } srq->msrq.max_avail_gather = (desc_size - sizeof(struct mlx5_wqe_srq_next_seg)) / sizeof(struct mlx5_wqe_data_seg); srq->msrq.wqe_shift = ilog2(desc_size); buf_size = srq->msrq.max * desc_size; - if (buf_size < desc_size) - return ERR_PTR(-EINVAL); + if (buf_size < desc_size) { + err = -EINVAL; + goto err_srq; + } in.type = init_attr->srq_type; if (pd->uobject) diff --git a/drivers/infiniband/sw/rxe/rxe_comp.c b/drivers/infiniband/sw/rxe/rxe_comp.c index 9eb12c2e3c74cf69499124e21fcb1b4a8be4a40f..83cfe44f070ec47d85f43a02e7ce4a44158bab35 100644 --- a/drivers/infiniband/sw/rxe/rxe_comp.c +++ b/drivers/infiniband/sw/rxe/rxe_comp.c @@ -276,6 +276,7 @@ static inline enum comp_state check_ack(struct rxe_qp *qp, case IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE: if (wqe->wr.opcode != IB_WR_RDMA_READ && wqe->wr.opcode != IB_WR_RDMA_READ_WITH_INV) { + wqe->status = IB_WC_FATAL_ERR; return COMPST_ERROR; } reset_retry_counters(qp); diff --git a/drivers/infiniband/sw/rxe/rxe_recv.c b/drivers/infiniband/sw/rxe/rxe_recv.c index fb8c83e055e14c653eb1f05f42a3265005d8d737..83412df726a5184cd049dea96d28724c13d3f6ae 100644 --- a/drivers/infiniband/sw/rxe/rxe_recv.c +++ b/drivers/infiniband/sw/rxe/rxe_recv.c @@ -225,9 +225,14 @@ static int hdr_check(struct rxe_pkt_info *pkt) goto err1; } + if (unlikely(qpn == 0)) { + pr_warn_once("QP 0 not supported"); + goto err1; + } + if (qpn != IB_MULTICAST_QPN) { - index = (qpn == 0) ? port->qp_smi_index : - ((qpn == 1) ? port->qp_gsi_index : qpn); + index = (qpn == 1) ? port->qp_gsi_index : qpn; + qp = rxe_pool_get_index(&rxe->qp_pool, index); if (unlikely(!qp)) { pr_warn_ratelimited("no qp matches qpn 0x%x\n", qpn); diff --git a/drivers/infiniband/sw/rxe/rxe_req.c b/drivers/infiniband/sw/rxe/rxe_req.c index 54cc9cb1e3b765b848782ad9779225a1dde7e1b6..de853bcc2384d92ede39f6f8d30c5c3749445d6d 100644 --- a/drivers/infiniband/sw/rxe/rxe_req.c +++ b/drivers/infiniband/sw/rxe/rxe_req.c @@ -645,6 +645,9 @@ int rxe_requester(void *arg) } else { goto exit; } + if ((wqe->wr.send_flags & IB_SEND_SIGNALED) || + qp->sq_sig_type == IB_SIGNAL_ALL_WR) + rxe_run_task(&qp->comp.task, 1); qp->req.wqe_index = next_index(qp->sq.queue, qp->req.wqe_index); goto next_wqe; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 7a5ed5a5391e12b1727a70faac5f0895e01b5b3a..9939f32d015487fc1ed8617d18e6f97f305751ba 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -1018,12 +1018,14 @@ static int ipoib_cm_rep_handler(struct ib_cm_id *cm_id, struct ib_cm_event *even skb_queue_head_init(&skqueue); + netif_tx_lock_bh(p->dev); spin_lock_irq(&priv->lock); set_bit(IPOIB_FLAG_OPER_UP, &p->flags); if (p->neigh) while ((skb = __skb_dequeue(&p->neigh->queue))) __skb_queue_tail(&skqueue, skb); spin_unlock_irq(&priv->lock); + netif_tx_unlock_bh(p->dev); while ((skb = __skb_dequeue(&skqueue))) { skb->dev = p->dev; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 6bc9a768f72193ef0a9b3ad00ed4e9f4da8f23d1..e6ff16b27acdb6c65a234c8536ffcdb87b690cd5 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -1752,7 +1752,8 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port) goto out_free_pd; } - if (ipoib_neigh_hash_init(priv) < 0) { + ret = ipoib_neigh_hash_init(priv); + if (ret) { pr_warn("%s failed to init neigh hash\n", dev->name); goto out_dev_uninit; } diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 299a97b7e17fff2982e8762e4620afb904683870..ade98c234dcb39e1c860bb8b7a115964ac61d540 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -2669,7 +2669,7 @@ static int srp_reset_device(struct scsi_cmnd *scmnd) { struct srp_target_port *target = host_to_target(scmnd->device->host); struct srp_rdma_ch *ch; - int i; + int i, j; u8 status; shost_printk(KERN_ERR, target->scsi_host, "SRP reset_device called\n"); @@ -2683,8 +2683,8 @@ static int srp_reset_device(struct scsi_cmnd *scmnd) for (i = 0; i < target->ch_count; i++) { ch = &target->ch[i]; - for (i = 0; i < target->req_ring_size; ++i) { - struct srp_request *req = &ch->req_ring[i]; + for (j = 0; j < target->req_ring_size; ++j) { + struct srp_request *req = &ch->req_ring[j]; srp_finish_req(ch, req, scmnd->device, DID_RESET << 16); } diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 2e7982042fe59e94efbb8870ed2bc414a3748374..7dbc0d9ad9a7656d9af03b016971d037bfce64c5 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -1713,8 +1713,7 @@ static bool srpt_close_ch(struct srpt_rdma_ch *ch) int ret; if (!srpt_set_ch_state(ch, CH_DRAINING)) { - pr_debug("%s-%d: already closed\n", ch->sess_name, - ch->qp->qp_num); + pr_debug("%s: already closed\n", ch->sess_name); return false; } diff --git a/drivers/input/input.c b/drivers/input/input.c index 762bfb9487dc961cf1c7d12a18a0d10dd3386b4c..50d425fe6706faf84596851a730a0e62b860d1cb 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -480,11 +480,19 @@ EXPORT_SYMBOL(input_inject_event); */ void input_alloc_absinfo(struct input_dev *dev) { - if (!dev->absinfo) - dev->absinfo = kcalloc(ABS_CNT, sizeof(*dev->absinfo), - GFP_KERNEL); + if (dev->absinfo) + return; - WARN(!dev->absinfo, "%s(): kcalloc() failed?\n", __func__); + dev->absinfo = kcalloc(ABS_CNT, sizeof(*dev->absinfo), GFP_KERNEL); + if (!dev->absinfo) { + dev_err(dev->dev.parent ?: &dev->dev, + "%s: unable to allocate memory\n", __func__); + /* + * We will handle this allocation failure in + * input_register_device() when we refuse to register input + * device with ABS bits but without absinfo. + */ + } } EXPORT_SYMBOL(input_alloc_absinfo); diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c index d91f3b1c53755f44dc9e6a469359d0173dbbf264..92d7396490225732c2aa54fa7951fe771187c82d 100644 --- a/drivers/input/misc/xen-kbdfront.c +++ b/drivers/input/misc/xen-kbdfront.c @@ -229,7 +229,7 @@ static int xenkbd_probe(struct xenbus_device *dev, } } - touch = xenbus_read_unsigned(dev->nodename, + touch = xenbus_read_unsigned(dev->otherend, XENKBD_FIELD_FEAT_MTOUCH, 0); if (touch) { ret = xenbus_write(XBT_NIL, dev->nodename, @@ -304,13 +304,13 @@ static int xenkbd_probe(struct xenbus_device *dev, if (!mtouch) goto error_nomem; - num_cont = xenbus_read_unsigned(info->xbdev->nodename, + num_cont = xenbus_read_unsigned(info->xbdev->otherend, XENKBD_FIELD_MT_NUM_CONTACTS, 1); - width = xenbus_read_unsigned(info->xbdev->nodename, + width = xenbus_read_unsigned(info->xbdev->otherend, XENKBD_FIELD_MT_WIDTH, XENFB_WIDTH); - height = xenbus_read_unsigned(info->xbdev->nodename, + height = xenbus_read_unsigned(info->xbdev->otherend, XENKBD_FIELD_MT_HEIGHT, XENFB_HEIGHT); diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index a250f433eb968b236ae2ddf99cf45f69d7f17fef..84c69e962230bc8f3fb739eb294d2e433147582f 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -1180,6 +1180,8 @@ static const struct dmi_system_id elantech_dmi_has_middle_button[] = { static const char * const middle_button_pnp_ids[] = { "LEN2131", /* ThinkPad P52 w/ NFC */ "LEN2132", /* ThinkPad P52 */ + "LEN2133", /* ThinkPad P72 w/ NFC */ + "LEN2134", /* ThinkPad P72 */ NULL }; diff --git a/drivers/input/rmi4/rmi_2d_sensor.c b/drivers/input/rmi4/rmi_2d_sensor.c index 8bb866c7b9855c5025d31b7be3f722d469f73da9..8eeffa066022dadb9f718f77aab1609700f05543 100644 --- a/drivers/input/rmi4/rmi_2d_sensor.c +++ b/drivers/input/rmi4/rmi_2d_sensor.c @@ -32,15 +32,15 @@ void rmi_2d_sensor_abs_process(struct rmi_2d_sensor *sensor, if (obj->type == RMI_2D_OBJECT_NONE) return; - if (axis_align->swap_axes) - swap(obj->x, obj->y); - if (axis_align->flip_x) obj->x = sensor->max_x - obj->x; if (axis_align->flip_y) obj->y = sensor->max_y - obj->y; + if (axis_align->swap_axes) + swap(obj->x, obj->y); + /* * Here checking if X offset or y offset are specified is * redundant. We just add the offsets or clip the values. @@ -120,15 +120,15 @@ void rmi_2d_sensor_rel_report(struct rmi_2d_sensor *sensor, int x, int y) x = min(RMI_2D_REL_POS_MAX, max(RMI_2D_REL_POS_MIN, (int)x)); y = min(RMI_2D_REL_POS_MAX, max(RMI_2D_REL_POS_MIN, (int)y)); - if (axis_align->swap_axes) - swap(x, y); - if (axis_align->flip_x) x = min(RMI_2D_REL_POS_MAX, -x); if (axis_align->flip_y) y = min(RMI_2D_REL_POS_MAX, -y); + if (axis_align->swap_axes) + swap(x, y); + if (x || y) { input_report_rel(sensor->input, REL_X, x); input_report_rel(sensor->input, REL_Y, y); @@ -141,17 +141,10 @@ static void rmi_2d_sensor_set_input_params(struct rmi_2d_sensor *sensor) struct input_dev *input = sensor->input; int res_x; int res_y; + int max_x, max_y; int input_flags = 0; if (sensor->report_abs) { - if (sensor->axis_align.swap_axes) { - swap(sensor->max_x, sensor->max_y); - swap(sensor->axis_align.clip_x_low, - sensor->axis_align.clip_y_low); - swap(sensor->axis_align.clip_x_high, - sensor->axis_align.clip_y_high); - } - sensor->min_x = sensor->axis_align.clip_x_low; if (sensor->axis_align.clip_x_high) sensor->max_x = min(sensor->max_x, @@ -163,14 +156,19 @@ static void rmi_2d_sensor_set_input_params(struct rmi_2d_sensor *sensor) sensor->axis_align.clip_y_high); set_bit(EV_ABS, input->evbit); - input_set_abs_params(input, ABS_MT_POSITION_X, 0, sensor->max_x, - 0, 0); - input_set_abs_params(input, ABS_MT_POSITION_Y, 0, sensor->max_y, - 0, 0); + + max_x = sensor->max_x; + max_y = sensor->max_y; + if (sensor->axis_align.swap_axes) + swap(max_x, max_y); + input_set_abs_params(input, ABS_MT_POSITION_X, 0, max_x, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, 0, max_y, 0, 0); if (sensor->x_mm && sensor->y_mm) { res_x = (sensor->max_x - sensor->min_x) / sensor->x_mm; res_y = (sensor->max_y - sensor->min_y) / sensor->y_mm; + if (sensor->axis_align.swap_axes) + swap(res_x, res_y); input_abs_set_res(input, ABS_X, res_x); input_abs_set_res(input, ABS_Y, res_y); diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index fc149ea64be795f92616a920dd9ee492291bab74..59aaac43db91f9784edafe7e9a5b2770fed0d98c 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -1647,10 +1647,11 @@ static int mxt_parse_object_table(struct mxt_data *data, break; case MXT_TOUCH_MULTI_T9: data->multitouch = MXT_TOUCH_MULTI_T9; + /* Only handle messages from first T9 instance */ data->T9_reportid_min = min_id; - data->T9_reportid_max = max_id; - data->num_touchids = object->num_report_ids - * mxt_obj_instances(object); + data->T9_reportid_max = min_id + + object->num_report_ids - 1; + data->num_touchids = object->num_report_ids; break; case MXT_SPT_MESSAGECOUNT_T44: data->T44_address = object->start_address; diff --git a/drivers/input/touchscreen/hxchipset/himax_common.c b/drivers/input/touchscreen/hxchipset/himax_common.c index d350f1c19a11dff926abe3e4c090720a23a8b09f..d9c72f47841bd0ece1924d2e0d11b187c259da77 100644 --- a/drivers/input/touchscreen/hxchipset/himax_common.c +++ b/drivers/input/touchscreen/hxchipset/himax_common.c @@ -47,29 +47,23 @@ struct himax_target_report_data *g_target_report_data; static int HX_TOUCH_INFO_POINT_CNT; -unsigned long FW_VER_MAJ_FLASH_ADDR; -unsigned long FW_VER_MIN_FLASH_ADDR; -unsigned long CFG_VER_MAJ_FLASH_ADDR; -unsigned long CFG_VER_MIN_FLASH_ADDR; -unsigned long CID_VER_MAJ_FLASH_ADDR; -unsigned long CID_VER_MIN_FLASH_ADDR; - -unsigned long FW_VER_MAJ_FLASH_LENG; -unsigned long FW_VER_MIN_FLASH_LENG; -unsigned long CFG_VER_MAJ_FLASH_LENG; -unsigned long CFG_VER_MIN_FLASH_LENG; -unsigned long CID_VER_MAJ_FLASH_LENG; -unsigned long CID_VER_MIN_FLASH_LENG; +/* Himax: Set FW and CFG Flash Address */ +#define FW_VER_MAJ_FLASH_ADDR 0x00C005 +#define FW_VER_MIN_FLASH_ADDR 0x00C006 +#define CFG_VER_MAJ_FLASH_ADDR 0x00C100 +#define CFG_VER_MIN_FLASH_ADDR 0x00C101 +#define CID_VER_MAJ_FLASH_ADDR 0x00C002 +#define CID_VER_MIN_FLASH_ADDR 0x00C003 + +#define FW_VER_MAJ_FLASH_LENG 1 +#define FW_VER_MIN_FLASH_LENG 1 +#define CFG_VER_MAJ_FLASH_LENG 1 +#define CFG_VER_MIN_FLASH_LENG 1 +#define CID_VER_MAJ_FLASH_LENG 1 +#define CID_VER_MIN_FLASH_LENG 1 unsigned long FW_CFG_VER_FLASH_ADDR; -#ifdef HX_AUTO_UPDATE_FW - int g_i_FW_VER = 0; - int g_i_CFG_VER = 0; - int g_i_CID_MAJ = 0; /* GUEST ID */ - int g_i_CID_MIN = 0; /* VER for GUEST */ -#endif - unsigned char IC_CHECKSUM; #ifdef HX_ESD_RECOVERY @@ -513,25 +507,32 @@ static int i_update_FW(void) int upgrade_times = 0; unsigned char *ImageBuffer = NULL; int fullFileLength = 0; - uint8_t ret = 0, result = 0; + int ret = 0, result = 0; + uint32_t i_FW_VER = 0, i_CFG_VER = 0; - himax_int_enable(0); - - I("file name = %s\n", i_CTPM_firmware_name); - ret = request_firmware(&i_CTPM_FW, i_CTPM_firmware_name, private_ts->dev); - if (ret < 0) { - E("%s,fail in line%d error code=%d\n", __func__, __LINE__, ret); + D("file name = %s\n", i_CTPM_firmware_name); + if (request_firmware(&i_CTPM_FW, i_CTPM_firmware_name, + private_ts->dev)) { + I("%s: no firmware file\n", __func__); return OPEN_FILE_FAIL; } - if (i_CTPM_FW != NULL) { - fullFileLength = i_CTPM_FW->size; - ImageBuffer = (unsigned char *)i_CTPM_FW->data; - } else { - I("%s: i_CTPM_FW = NULL\n", __func__); - return OPEN_FILE_FAIL; + fullFileLength = i_CTPM_FW->size; + ImageBuffer = (unsigned char *)i_CTPM_FW->data; + + i_FW_VER = (ImageBuffer[FW_VER_MAJ_FLASH_ADDR] << 8) + | ImageBuffer[FW_VER_MIN_FLASH_ADDR]; + i_CFG_VER = (ImageBuffer[CFG_VER_MAJ_FLASH_ADDR] << 8) + | ImageBuffer[CFG_VER_MIN_FLASH_ADDR]; + + if ((ic_data->vendor_fw_ver >= i_FW_VER) + && (ic_data->vendor_config_ver >= i_CFG_VER)) { + D("FW_VER 0x%x, CFG_VER 0x%x\n", i_FW_VER, i_CFG_VER); + release_firmware(i_CTPM_FW); + return 0; } + himax_int_enable(0); update_retry: if (fullFileLength == FW_SIZE_32k) @@ -559,7 +560,7 @@ static int i_update_FW(void) g_core_fp.fp_read_FW_ver(); g_core_fp.fp_touch_information(); result = 1;/* upgrade success */ - I("%s: TP upgrade OK\n", __func__); + D("%s: TP upgrade OK\n", __func__); } #ifdef HX_RST_PIN_FUNC @@ -1618,20 +1619,19 @@ static void himax_finger_report(struct himax_ts_data *ts) g_target_report_data->x[i], g_target_report_data->y[i], g_target_report_data->w[i]); #ifndef HX_PROTOCOL_A input_mt_slot(ts->input_dev, i); + ts->last_slot = i; + input_mt_report_slot_state(ts->input_dev, + MT_TOOL_FINGER, 1); #endif input_report_key(ts->input_dev, BTN_TOUCH, g_target_report_data->finger_on); input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, g_target_report_data->w[i]); - input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, i); #ifndef HX_PROTOCOL_A input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, g_target_report_data->w[i]); input_report_abs(ts->input_dev, ABS_MT_PRESSURE, g_target_report_data->w[i]); #endif input_report_abs(ts->input_dev, ABS_MT_POSITION_X, g_target_report_data->x[i]); input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, g_target_report_data->y[i]); -#ifndef HX_PROTOCOL_A - ts->last_slot = i; - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 1); -#else +#ifdef HX_PROTOCOL_A input_mt_sync(ts->input_dev); #endif @@ -1888,15 +1888,14 @@ static const struct t_cable_status_notifier himax_cable_status_handler = { #endif #ifdef HX_AUTO_UPDATE_FW -static void himax_update_register(struct work_struct *work) +void himax_update_register(struct work_struct *work) { - I(" %s in", __func__); + D(" %s in", __func__); if (i_update_FW() <= 0) - I("FW =NOT UPDATE=\n"); + D("FW =NOT UPDATE=\n"); else - I("Have new FW =UPDATE=\n"); - + D("Have new FW =UPDATE=\n"); } #endif @@ -2009,29 +2008,11 @@ int himax_chip_common_init(void) if (pdata->virtual_key) ts->button = pdata->virtual_key; -#ifdef HX_AUTO_UPDATE_FW - auto_update_flag = (!g_core_fp.fp_calculateChecksum(false)); - auto_update_flag |= g_core_fp.fp_flash_lastdata_check(); - if (auto_update_flag) - goto FW_force_upgrade; -#endif g_core_fp.fp_read_FW_ver(); #ifdef HX_AUTO_UPDATE_FW -FW_force_upgrade: - auto_update_flag |= ((ic_data->vendor_fw_ver < g_i_FW_VER) || (ic_data->vendor_config_ver < g_i_CFG_VER)); - /* Not sure to do */ - /* auto_update_flag |= ((ic_data->vendor_cid_maj_ver != g_i_CID_MAJ) || (ic_data->vendor_cid_min_ver < g_i_CID_MIN)); */ - if (auto_update_flag) { - ts->himax_update_wq = create_singlethread_workqueue("HMX_update_request"); - if (!ts->himax_update_wq) { - E(" allocate syn_update_wq failed\n"); - err = -ENOMEM; - goto err_update_wq_failed; - } - INIT_DELAYED_WORK(&ts->work_update, himax_update_register); - queue_delayed_work(ts->himax_update_wq, &ts->work_update, msecs_to_jiffies(2000)); - } + queue_delayed_work(ts->himax_update_wq, &ts->work_update, + msecs_to_jiffies(2000)); #endif #ifdef HX_ZERO_FLASH auto_update_flag = true; @@ -2136,12 +2117,7 @@ int himax_chip_common_init(void) E(" %s: debug initial failed!\n", __func__); #endif -#if defined(HX_AUTO_UPDATE_FW) || defined(HX_ZERO_FLASH) - - if (auto_update_flag) - himax_int_enable(0); -#endif return 0; err_register_interrupt_failed: remove_proc_entry(HIMAX_PROC_TOUCH_FOLDER, NULL); @@ -2162,7 +2138,7 @@ remove_proc_entry(HIMAX_PROC_TOUCH_FOLDER, NULL); cancel_delayed_work_sync(&ts->work_update); destroy_workqueue(ts->himax_update_wq); } -err_update_wq_failed: + #endif error_ic_detect_failed: @@ -2240,7 +2216,7 @@ void himax_chip_common_deinit(void) kfree(hx_touch_data); kfree(ic_data); kfree(ts->pdata); - kfree(ts->report_i2c_data); + kfree(ts->i2c_data); kfree(ts); probe_fail_flag = 0; } diff --git a/drivers/input/touchscreen/hxchipset/himax_common.h b/drivers/input/touchscreen/hxchipset/himax_common.h index 6d48fe782ce7e85e37f75109810a94ab634302bb..8830e2c0fc1690331d2e4f14385b001ecc1e5102 100644 --- a/drivers/input/touchscreen/hxchipset/himax_common.h +++ b/drivers/input/touchscreen/hxchipset/himax_common.h @@ -66,7 +66,7 @@ #define HX_RST_PIN_FUNC #define HX_RESUME_SEND_CMD #define HX_ESD_RECOVERY -/*#define HX_AUTO_UPDATE_FW*/ +#define HX_AUTO_UPDATE_FW /*#define HX_SMART_WAKEUP*/ /*#define HX_GESTURE_TRACK*/ /*#define HX_HIGH_SENSE*/ @@ -143,6 +143,7 @@ #define HX_FINGER_LEAVE 2 #define HX_REPORT_SZ 128 +#define HX_CMD_BYTE 1 enum HX_TS_PATH { HX_REPORT_COORD = 1, @@ -364,7 +365,7 @@ struct himax_ts_data { struct work_struct ito_test_work; #endif - uint8_t *report_i2c_data; + uint8_t *i2c_data; /* for I2C DMA transfer */ }; struct himax_debug { @@ -438,14 +439,6 @@ extern struct himax_core_fp g_core_fp; extern struct himax_debug *debug_data; extern uint8_t HX_PROC_SEND_FLAG; -#ifdef HX_AUTO_UPDATE_FW -extern int g_i_FW_VER; -extern int g_i_CFG_VER; -extern int g_i_CID_MAJ; /* GUEST ID */ -extern int g_i_CID_MIN; /* VER for GUEST */ -extern unsigned char i_CTPM_FW[]; -#endif - extern unsigned long FW_VER_MAJ_FLASH_ADDR; extern unsigned long FW_VER_MIN_FLASH_ADDR; extern unsigned long CFG_VER_MAJ_FLASH_ADDR; @@ -495,5 +488,7 @@ extern struct himax_target_report_data *g_target_report_data; extern int himax_report_data(struct himax_ts_data *ts, int ts_path, int ts_status); /* ts_work about end */ +void himax_update_register(struct work_struct *work); + #endif diff --git a/drivers/input/touchscreen/hxchipset/himax_ic_HX83112.c b/drivers/input/touchscreen/hxchipset/himax_ic_HX83112.c index 14604dc1eb95cc15abb2295f7ce3cff5bd7256e9..bc927f87e3e1f345d2105308f4b9787f995c3750 100644 --- a/drivers/input/touchscreen/hxchipset/himax_ic_HX83112.c +++ b/drivers/input/touchscreen/hxchipset/himax_ic_HX83112.c @@ -188,26 +188,6 @@ static void hx83112_chip_init(void) private_ts->chip_cell_type = CHIP_IS_IN_CELL; D("%s:IC cell type = %d\n", __func__, private_ts->chip_cell_type); IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; - /* Himax: Set FW and CFG Flash Address */ - FW_VER_MAJ_FLASH_ADDR = 49157; /* 0x00C005 */ - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 49158; /* 0x00C006 */ - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 49408; /* 0x00C100 */ - CFG_VER_MAJ_FLASH_LENG = 1; - CFG_VER_MIN_FLASH_ADDR = 49409; /* 0x00C101 */ - CFG_VER_MIN_FLASH_LENG = 1; - CID_VER_MAJ_FLASH_ADDR = 49154; /* 0x00C002 */ - CID_VER_MAJ_FLASH_LENG = 1; - CID_VER_MIN_FLASH_ADDR = 49155; /* 0x00C003 */ - CID_VER_MIN_FLASH_LENG = 1; - -#ifdef HX_AUTO_UPDATE_FW - g_i_FW_VER = (i_CTPM_FW[FW_VER_MAJ_FLASH_ADDR] << 8) | i_CTPM_FW[FW_VER_MIN_FLASH_ADDR]; - g_i_CFG_VER = (i_CTPM_FW[CFG_VER_MAJ_FLASH_ADDR] << 8) | i_CTPM_FW[CFG_VER_MIN_FLASH_ADDR]; - g_i_CID_MAJ = i_CTPM_FW[CID_VER_MAJ_FLASH_ADDR]; - g_i_CID_MIN = i_CTPM_FW[CID_VER_MIN_FLASH_ADDR]; -#endif } #ifdef CONFIG_CHIP_DTCFG diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.c b/drivers/input/touchscreen/hxchipset/himax_platform.c index a32b7ccfd26b7d67cb3ea41d263c786e4df20e41..e1ea6a47f43915efa2a81698c8890fe4b727e4c9 100644 --- a/drivers/input/touchscreen/hxchipset/himax_platform.c +++ b/drivers/input/touchscreen/hxchipset/himax_platform.c @@ -16,6 +16,7 @@ #include "himax_platform.h" #include "himax_common.h" +#include "himax_ic_core.h" int i2c_error_count; int irq_enable_count; @@ -172,35 +173,38 @@ int himax_bus_read(uint8_t command, uint8_t *data, uint32_t length, uint8_t toRe int retry; bool reallocate = false; struct himax_ts_data *ts = private_ts; - uint8_t *buf = ts->report_i2c_data; + uint8_t *buf = ts->i2c_data; struct i2c_client *client = ts->client; struct i2c_msg msg[] = { { .addr = client->addr, .flags = 0, - .len = 1, - .buf = &command, + .len = HX_CMD_BYTE, + .buf = buf, }, { .addr = client->addr, .flags = I2C_M_RD, .len = length, - .buf = buf, + .buf = buf + HX_CMD_BYTE, } }; - if (length > HX_REPORT_SZ * 2) { - I("%s: data length too large %d\n", __func__, length); - buf = kmalloc(length, GFP_KERNEL); + if (length > FLASH_RW_MAX_LEN) { + W("%s: data length too large %d!\n", __func__, length); + buf = kmalloc(length + HX_CMD_BYTE, GFP_KERNEL); if (!buf) { - E("%s: failed realloc buf %d\n", __func__, length); + E("%s: failed realloc buf %d\n", __func__, + length + HX_CMD_BYTE); return -EIO; } reallocate = true; - msg[1].buf = buf; + msg[0].buf = buf; + msg[1].buf = buf + HX_CMD_BYTE; } mutex_lock(&ts->rw_lock); + buf[0] = command; for (retry = 0; retry < toRetry; retry++) { if (i2c_transfer(client->adapter, msg, 2) == 2) @@ -216,7 +220,7 @@ int himax_bus_read(uint8_t command, uint8_t *data, uint32_t length, uint8_t toRe return -EIO; } - memcpy(data, buf, length); + memcpy(data, buf + HX_CMD_BYTE, length); mutex_unlock(&ts->rw_lock); if (reallocate) @@ -230,30 +234,32 @@ int himax_bus_write(uint8_t command, uint8_t *data, uint32_t length, uint8_t toR int retry; bool reallocate = false; struct himax_ts_data *ts = private_ts; - uint8_t *buf = ts->report_i2c_data; + uint8_t *buf = ts->i2c_data; struct i2c_client *client = ts->client; struct i2c_msg msg[] = { { .addr = client->addr, .flags = 0, - .len = length + 1, + .len = length + HX_CMD_BYTE, .buf = buf, } }; - if (length + 1 > HX_REPORT_SZ * 2) { - I("%s: data length too large %d\n", __func__, length + 1); - buf = kmalloc(length + 1, GFP_KERNEL); + if (length > FLASH_RW_MAX_LEN) { + W("%s: data length too large %d!\n", __func__, length); + buf = kmalloc(length + HX_CMD_BYTE, GFP_KERNEL); if (!buf) { - E("%s: failed realloc buf %d\n", __func__, length + 1); + E("%s: failed realloc buf %d\n", __func__, + length + HX_CMD_BYTE); return -EIO; } reallocate = true; + msg[0].buf = buf; } mutex_lock(&ts->rw_lock); buf[0] = command; - memcpy(buf + 1, data, length); + memcpy(buf + HX_CMD_BYTE, data, length); for (retry = 0; retry < toRetry; retry++) { if (i2c_transfer(client->adapter, msg, 1) == 1) @@ -287,7 +293,7 @@ int himax_bus_master_write(uint8_t *data, uint32_t length, uint8_t toRetry) int retry; bool reallocate = false; struct himax_ts_data *ts = private_ts; - uint8_t *buf = ts->report_i2c_data; + uint8_t *buf = ts->i2c_data; struct i2c_client *client = private_ts->client; struct i2c_msg msg[] = { { @@ -298,14 +304,15 @@ int himax_bus_master_write(uint8_t *data, uint32_t length, uint8_t toRetry) } }; - if (length > HX_REPORT_SZ * 2) { - I("%s: data length too large %d\n", __func__, length); + if (length > FLASH_RW_MAX_LEN) { + W("%s: data length too large %d!\n", __func__, length); buf = kmalloc(length, GFP_KERNEL); if (!buf) { E("%s: failed realloc buf %d\n", __func__, length); return -EIO; } reallocate = true; + msg[0].buf = buf; } mutex_lock(&ts->rw_lock); @@ -719,13 +726,10 @@ int drm_notifier_callback(struct notifier_block *self, D("DRM %s\n", __func__); - if (evdata->data && event == MSM_DRM_EVENT_BLANK && ts && ts->client) { + if (evdata->data && event == MSM_DRM_EARLY_EVENT_BLANK && ts && + ts->client) { blank = evdata->data; - switch (*blank) { - case MSM_DRM_BLANK_UNBLANK: - himax_common_resume(&ts->client->dev); - break; case MSM_DRM_BLANK_POWERDOWN: if (!ts->initialized) return -ECANCELED; @@ -734,6 +738,15 @@ int drm_notifier_callback(struct notifier_block *self, } } + if (evdata->data && event == MSM_DRM_EVENT_BLANK && ts && ts->client) { + blank = evdata->data; + switch (*blank) { + case MSM_DRM_BLANK_UNBLANK: + himax_common_resume(&ts->client->dev); + break; + } + } + return 0; } @@ -797,11 +810,11 @@ int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_i mutex_init(&ts->rw_lock); private_ts = ts; - ts->report_i2c_data = kmalloc(HX_REPORT_SZ * 2, GFP_KERNEL); - if (ts->report_i2c_data == NULL) { - E("%s: allocate report_i2c_data failed\n", __func__); + ts->i2c_data = kmalloc(FLASH_RW_MAX_LEN + HX_CMD_BYTE, GFP_KERNEL); + if (ts->i2c_data == NULL) { + E("%s: allocate i2c_data failed\n", __func__); ret = -ENOMEM; - goto err_report_i2c_data; + goto err_alloc_i2c_data; } /* @@ -815,11 +828,20 @@ int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_i goto err_fb_notify_reg_failed; #endif +#ifdef HX_AUTO_UPDATE_FW + ts->himax_update_wq = + create_singlethread_workqueue("HMX_update_request"); + if (!ts->himax_update_wq) { + E(" allocate syn_update_wq failed\n"); + goto err_fb_notify_reg_failed; + } + INIT_DELAYED_WORK(&ts->work_update, himax_update_register); +#endif return ret; err_fb_notify_reg_failed: - kfree(ts->report_i2c_data); -err_report_i2c_data: + kfree(ts->i2c_data); +err_alloc_i2c_data: kfree(ts); err_alloc_data_failed: err_check_functionality_failed: diff --git a/drivers/input/touchscreen/rohm_bu21023.c b/drivers/input/touchscreen/rohm_bu21023.c index eeaf6ff035974c836668a0aaec55fb4bd0f05965..fc54e044fecef7be51d394a0ce92620cfe14a529 100644 --- a/drivers/input/touchscreen/rohm_bu21023.c +++ b/drivers/input/touchscreen/rohm_bu21023.c @@ -304,7 +304,7 @@ static int rohm_i2c_burst_read(struct i2c_client *client, u8 start, void *buf, msg[1].len = len; msg[1].buf = buf; - i2c_lock_adapter(adap); + i2c_lock_bus(adap, I2C_LOCK_SEGMENT); for (i = 0; i < 2; i++) { if (__i2c_transfer(adap, &msg[i], 1) < 0) { @@ -313,7 +313,7 @@ static int rohm_i2c_burst_read(struct i2c_client *client, u8 start, void *buf, } } - i2c_unlock_adapter(adap); + i2c_unlock_bus(adap, I2C_LOCK_SEGMENT); return ret; } diff --git a/drivers/input/touchscreen/st/fts.c b/drivers/input/touchscreen/st/fts.c index e5d3542c75ef680cb36289595043c3795393beb7..1c6e32e6ed96b0966acb98ab9b8354deea3fe4f8 100644 --- a/drivers/input/touchscreen/st/fts.c +++ b/drivers/input/touchscreen/st/fts.c @@ -4678,6 +4678,8 @@ static int fts_probe(struct i2c_client *client, ProbeErrorExit_3: fts_enable_reg(info, false); + fts_gpio_setup(info->bdata->irq_gpio, false, 0, 0); + fts_gpio_setup(info->bdata->reset_gpio, false, 0, 0); ProbeErrorExit_2: fts_get_reg(info, false); @@ -4737,6 +4739,9 @@ static int fts_remove(struct i2c_client *client) destroy_workqueue(info->fwu_workqueue); fts_enable_reg(info, false); + fts_gpio_setup(info->bdata->irq_gpio, false, 0, 0); + fts_gpio_setup(info->bdata->reset_gpio, false, 0, 0); + fts_get_reg(info, false); /* free all */ diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c index 740ccfe5d3071debdc9dc96829d13ea87ead17c1..5fa4cf353b140316a11267db6524920af0ec3bab 100644 --- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c +++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_core.c @@ -4643,14 +4643,21 @@ static int synaptics_rmi4_dsi_panel_notifier_cb(struct notifier_block *self, return 0; if (evdata && evdata->data && rmi4_data) { - if (event == MSM_DRM_EVENT_BLANK) { + if (event == MSM_DRM_EARLY_EVENT_BLANK) { transition = *(int *)evdata->data; if (transition == MSM_DRM_BLANK_POWERDOWN) { if (rmi4_data->initialized) synaptics_rmi4_suspend( &rmi4_data->pdev->dev); rmi4_data->fb_ready = false; - } else if (transition == MSM_DRM_BLANK_UNBLANK) { + } + } + } + + if (evdata && evdata->data && rmi4_data) { + if (event == MSM_DRM_EVENT_BLANK) { + transition = *(int *)evdata->data; + if (transition == MSM_DRM_BLANK_UNBLANK) { if (rmi4_data->initialized) synaptics_rmi4_resume( &rmi4_data->pdev->dev); diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index 97a147ee94154e2ab502dc362d1f4521614c9db4..a0320bf64804a38bdb0b48b4dc89d8ca84920638 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -361,6 +361,16 @@ config ARM_SMMU_V3 Say Y here if your system includes an IOMMU device implementing the ARM SMMUv3 architecture. +config ARM_SMMU_SELFTEST + bool "ARM SMMU self test support" + depends on ARM_SMMU + help + Enables self tests for arm smmu. Tests basic hardware + configurations like interrupts. Note that enabling this + option can marginally increase the boot time. + + If unsure, say N here. + config QCOM_LAZY_MAPPING bool "Reference counted iommu-mapping support" depends on ION diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 10190e361a13db31135f3a7c44cc60a8ea1a6135..9137030423cdcaa8bfe658c57552c9ced82fad0f 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -2400,9 +2400,9 @@ static void __unmap_single(struct dma_ops_domain *dma_dom, } if (amd_iommu_unmap_flush) { - dma_ops_free_iova(dma_dom, dma_addr, pages); domain_flush_tlb(&dma_dom->domain); domain_flush_complete(&dma_dom->domain); + dma_ops_free_iova(dma_dom, dma_addr, pages); } else { pages = __roundup_pow_of_two(pages); queue_iova(&dma_dom->iovad, dma_addr >> PAGE_SHIFT, pages, 0); @@ -3071,7 +3071,7 @@ static phys_addr_t amd_iommu_iova_to_phys(struct iommu_domain *dom, return 0; offset_mask = pte_pgsize - 1; - __pte = *pte & PM_ADDR_MASK; + __pte = __sme_clr(*pte & PM_ADDR_MASK); return (__pte & ~offset_mask) | (iova & offset_mask); } diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index fa58f40607518a702f00e5d147b79629a4e5e0e1..56135f4525cac65c722b402128479dc645f65e56 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -1272,6 +1272,7 @@ static irqreturn_t arm_smmu_priq_thread(int irq, void *dev) /* Sync our overflow flag, as we believe we're up to speed */ q->cons = Q_OVF(q, q->prod) | Q_WRP(q, q->cons) | Q_IDX(q, q->cons); + writel(q->cons, q->cons_reg); return IRQ_HANDLED; } diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index bdc5e032b7831ed2fa98241fdec5796c5e5871f3..1a528f4da08acb28c05856904598370ef7888b55 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -55,6 +55,8 @@ #include #include #include +#include +#include #include @@ -525,6 +527,108 @@ static bool arm_smmu_opt_hibernation(struct arm_smmu_device *smmu) return IS_ENABLED(CONFIG_HIBERNATION); } +#ifdef CONFIG_ARM_SMMU_SELFTEST + +static int selftest; +module_param_named(selftest, selftest, int, 0644); +static int irq_count; + +static DECLARE_WAIT_QUEUE_HEAD(wait_int); +static irqreturn_t arm_smmu_cf_selftest(int irq, void *cb_base) +{ + u32 fsr; + struct irq_data *irq_data = irq_get_irq_data(irq); + unsigned long hwirq = ULONG_MAX; + + fsr = readl_relaxed(cb_base + ARM_SMMU_CB_FSR); + + irq_count++; + if (irq_data) + hwirq = irq_data->hwirq; + pr_info("Interrupt (irq:%d hwirq:%ld) received, fsr:0x%x\n", + irq, hwirq, fsr); + + writel_relaxed(fsr, cb_base + ARM_SMMU_CB_FSR); + + wake_up(&wait_int); + return IRQ_HANDLED; +} + +static void arm_smmu_interrupt_selftest(struct arm_smmu_device *smmu) +{ + int cb; + int cb_count = 0; + + if (!selftest) + return; + + if (arm_smmu_is_static_cb(smmu)) + return; + + cb = smmu->num_s2_context_banks; + + if (smmu->version < ARM_SMMU_V2) + return; + + for_each_clear_bit_from(cb, smmu->context_map, + smmu->num_context_banks) { + int irq; + int ret; + void *cb_base; + u32 reg; + u32 reg_orig; + int irq_cnt; + + irq = smmu->irqs[smmu->num_global_irqs + cb]; + cb_base = ARM_SMMU_CB(smmu, cb); + + ret = devm_request_threaded_irq(smmu->dev, irq, NULL, + arm_smmu_cf_selftest, + IRQF_ONESHOT | IRQF_SHARED, + "arm-smmu-context-fault", cb_base); + if (ret < 0) { + dev_err(smmu->dev, + "Failed to request cntx IRQ %d (%u)\n", + cb, irq); + continue; + } + + cb_count++; + irq_cnt = irq_count; + + reg_orig = readl_relaxed(cb_base + ARM_SMMU_CB_SCTLR); + reg = reg_orig | SCTLR_CFIE | SCTLR_CFRE; + + writel_relaxed(reg, cb_base + ARM_SMMU_CB_SCTLR); + dev_info(smmu->dev, "Testing cntx %d irq %d\n", cb, irq); + + /* Make sure ARM_SMMU_CB_SCTLR is configured */ + wmb(); + writel_relaxed(FSR_TF, cb_base + ARM_SMMU_CB_FSRRESTORE); + + wait_event_timeout(wait_int, (irq_count > irq_cnt), + msecs_to_jiffies(1000)); + + /* Make sure ARM_SMMU_CB_FSRRESTORE is written to */ + wmb(); + writel_relaxed(reg_orig, cb_base + ARM_SMMU_CB_SCTLR); + devm_free_irq(smmu->dev, irq, cb_base); + } + + dev_info(smmu->dev, + "Interrupt selftest completed...\n"); + dev_info(smmu->dev, + "Tested %d contexts, received %d interrupts\n", + cb_count, irq_count); + WARN_ON(cb_count != irq_count); + irq_count = 0; +} +#else +static void arm_smmu_interrupt_selftest(struct arm_smmu_device *smmu) +{ +} +#endif + /* * init() * Hook for additional device tree parsing at probe time. @@ -2319,7 +2423,10 @@ static void arm_smmu_domain_remove_master(struct arm_smmu_domain *smmu_domain, mutex_lock(&smmu->stream_map_mutex); for_each_cfg_sme(fwspec, i, idx) { - WARN_ON(s2cr[idx].attach_count == 0); + if (WARN_ON(s2cr[idx].attach_count == 0)) { + mutex_unlock(&smmu->stream_map_mutex); + return; + } s2cr[idx].attach_count -= 1; if (s2cr[idx].attach_count > 0) @@ -4711,12 +4818,15 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) if (err) goto out_power_off; - if (smmu->version == ARM_SMMU_V2 && - smmu->num_context_banks != smmu->num_context_irqs) { - dev_err(dev, - "found %d context interrupt(s) but have %d context banks. assuming %d context interrupts.\n", - smmu->num_context_irqs, smmu->num_context_banks, - smmu->num_context_banks); + if (smmu->version == ARM_SMMU_V2) { + if (smmu->num_context_banks > smmu->num_context_irqs) { + dev_err(dev, + "found %d context irq(s) but have %d context banks. assuming %d context interrupts.\n", + smmu->num_context_irqs, smmu->num_context_banks, + smmu->num_context_banks); + } + + /* Ignore superfluous interrupts */ smmu->num_context_irqs = smmu->num_context_banks; } @@ -4748,6 +4858,7 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) platform_set_drvdata(pdev, smmu); arm_smmu_device_reset(smmu); arm_smmu_test_smr_masks(smmu); + arm_smmu_interrupt_selftest(smmu); arm_smmu_power_off(smmu->pwr); /* diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index c458e26743e78bb5a102f7e3a92628272ebaa72c..3b1d92402d375891ba7b175fa47a05ffa6121d52 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -451,7 +451,7 @@ static dma_addr_t iommu_dma_alloc_iova(struct iommu_domain *domain, ret_iova = (dma_addr_t)iova << shift; - if (guard_len && + if (ret_iova && guard_len && iommu_map(domain, ret_iova + size, page_to_phys(cookie->guard_page), guard_len, ARM_SMMU_GUARD_PROT)) { diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index e3dbb6101b4a78fae47a093ddb2c365e4cb3d7af..c0d1c4db5794482c384b4bb6a5f5bd0dde1dab50 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -1336,8 +1336,8 @@ void qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr, qi_submit_sync(&desc, iommu); } -void qi_flush_dev_iotlb(struct intel_iommu *iommu, u16 sid, u16 qdep, - u64 addr, unsigned mask) +void qi_flush_dev_iotlb(struct intel_iommu *iommu, u16 sid, u16 pfsid, + u16 qdep, u64 addr, unsigned mask) { struct qi_desc desc; @@ -1352,7 +1352,7 @@ void qi_flush_dev_iotlb(struct intel_iommu *iommu, u16 sid, u16 qdep, qdep = 0; desc.low = QI_DEV_IOTLB_SID(sid) | QI_DEV_IOTLB_QDEP(qdep) | - QI_DIOTLB_TYPE; + QI_DIOTLB_TYPE | QI_DEV_IOTLB_PFSID(pfsid); qi_submit_sync(&desc, iommu); } diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index e8414bcf83904422be5aa819d41d9dd834d6d290..aaf3fed9747712500a3b7fe564beec81aaf422c5 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -422,6 +422,7 @@ struct device_domain_info { struct list_head global; /* link to global list */ u8 bus; /* PCI bus number */ u8 devfn; /* PCI devfn number */ + u16 pfsid; /* SRIOV physical function source ID */ u8 pasid_supported:3; u8 pasid_enabled:1; u8 pri_supported:1; @@ -1502,6 +1503,20 @@ static void iommu_enable_dev_iotlb(struct device_domain_info *info) return; pdev = to_pci_dev(info->dev); + /* For IOMMU that supports device IOTLB throttling (DIT), we assign + * PFSID to the invalidation desc of a VF such that IOMMU HW can gauge + * queue depth at PF level. If DIT is not set, PFSID will be treated as + * reserved, which should be set to 0. + */ + if (!ecap_dit(info->iommu->ecap)) + info->pfsid = 0; + else { + struct pci_dev *pf_pdev; + + /* pdev will be returned if device is not a vf */ + pf_pdev = pci_physfn(pdev); + info->pfsid = PCI_DEVID(pf_pdev->bus->number, pf_pdev->devfn); + } #ifdef CONFIG_INTEL_IOMMU_SVM /* The PCIe spec, in its wisdom, declares that the behaviour of @@ -1567,7 +1582,8 @@ static void iommu_flush_dev_iotlb(struct dmar_domain *domain, sid = info->bus << 8 | info->devfn; qdep = info->ats_qdep; - qi_flush_dev_iotlb(info->iommu, sid, qdep, addr, mask); + qi_flush_dev_iotlb(info->iommu, sid, info->pfsid, + qdep, addr, mask); } spin_unlock_irqrestore(&device_domain_lock, flags); } diff --git a/drivers/iommu/io-pgtable-arm-v7s.c b/drivers/iommu/io-pgtable-arm-v7s.c index 6961fc393f0b25828f5981fad35ea744c7768b41..29b7a6755fcdaabfee66f9444b8193d4b6400cf6 100644 --- a/drivers/iommu/io-pgtable-arm-v7s.c +++ b/drivers/iommu/io-pgtable-arm-v7s.c @@ -192,6 +192,7 @@ static void *__arm_v7s_alloc_table(int lvl, gfp_t gfp, { struct io_pgtable_cfg *cfg = &data->iop.cfg; struct device *dev = cfg->iommu_dev; + phys_addr_t phys; dma_addr_t dma; size_t size = ARM_V7S_TABLE_SIZE(lvl); void *table = NULL; @@ -200,6 +201,10 @@ static void *__arm_v7s_alloc_table(int lvl, gfp_t gfp, table = (void *)__get_dma_pages(__GFP_ZERO, get_order(size)); else if (lvl == 2) table = kmem_cache_zalloc(data->l2_tables, gfp | GFP_DMA); + phys = virt_to_phys(table); + if (phys != (arm_v7s_iopte)phys) + /* Doesn't fit in PTE */ + goto out_free; if (table && !(cfg->quirks & IO_PGTABLE_QUIRK_NO_DMA)) { dma = dma_map_single(dev, table, size, DMA_TO_DEVICE); if (dma_mapping_error(dev, dma)) @@ -209,7 +214,7 @@ static void *__arm_v7s_alloc_table(int lvl, gfp_t gfp, * address directly, so if the DMA layer suggests otherwise by * translating or truncating them, that bodes very badly... */ - if (dma != virt_to_phys(table)) + if (dma != phys) goto out_unmap; } kmemleak_ignore(table); diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c index 9fe93ce8d0aec451c87e5fa1ff22eee86658c4ac..f008234a3930bc82ec9756511d012ba01e196d90 100644 --- a/drivers/iommu/iommu-debug.c +++ b/drivers/iommu/iommu-debug.c @@ -297,6 +297,7 @@ static void iommu_debug_device_profiling(struct seq_file *s, struct device *dev, } } + domain->is_debug_domain = true; if (iommu_attach_group(domain, dev->iommu_group)) { seq_puts(s, "Couldn't attach new domain to device. Is it already attached?\n"); @@ -551,6 +552,7 @@ static int iommu_debug_profiling_fast_dma_api_show(struct seq_file *s, goto out_release_mapping; } + mapping->domain->is_debug_domain = true; if (arm_iommu_attach_device(dev, mapping)) { seq_puts(s, "fast_smmu_attach_device failed\n"); goto out_release_mapping; @@ -1173,6 +1175,7 @@ static int __apply_to_new_mapping(struct seq_file *s, goto out_release_mapping; } + mapping->domain->is_debug_domain = true; if (arm_iommu_attach_device(dev, mapping)) goto out_release_mapping; @@ -1239,6 +1242,7 @@ static int iommu_debug_functional_arm_dma_api_show(struct seq_file *s, if (!mapping) goto out; + mapping->domain->is_debug_domain = true; if (arm_iommu_attach_device(dev, mapping)) goto out_release_mapping; diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index 195d6e93ac7185aa53ee075521faf0de56ec53bf..5d0ba5f644c48ca89910102b01c8362fd0b796cf 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c @@ -54,7 +54,7 @@ struct ipmmu_vmsa_domain { struct io_pgtable_ops *iop; unsigned int context_id; - spinlock_t lock; /* Protects mappings */ + struct mutex mutex; /* Protects mappings */ }; struct ipmmu_vmsa_iommu_priv { @@ -523,7 +523,7 @@ static struct iommu_domain *__ipmmu_domain_alloc(unsigned type) if (!domain) return NULL; - spin_lock_init(&domain->lock); + mutex_init(&domain->mutex); return &domain->io_domain; } @@ -548,7 +548,6 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain, struct iommu_fwspec *fwspec = dev->iommu_fwspec; struct ipmmu_vmsa_device *mmu = priv->mmu; struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain); - unsigned long flags; unsigned int i; int ret = 0; @@ -557,7 +556,7 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain, return -ENXIO; } - spin_lock_irqsave(&domain->lock, flags); + mutex_lock(&domain->mutex); if (!domain->mmu) { /* The domain hasn't been used yet, initialize it. */ @@ -574,7 +573,7 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain, } else dev_info(dev, "Reusing IPMMU context %u\n", domain->context_id); - spin_unlock_irqrestore(&domain->lock, flags); + mutex_unlock(&domain->mutex); if (ret < 0) return ret; diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c index 04f4d51ffacb1e50ae3f87f04fd3b23306f7b55b..92c8c83ce38c3624359c1906d5a649641c02d81a 100644 --- a/drivers/iommu/msm_iommu.c +++ b/drivers/iommu/msm_iommu.c @@ -395,20 +395,15 @@ static int msm_iommu_add_device(struct device *dev) struct msm_iommu_dev *iommu; struct iommu_group *group; unsigned long flags; - int ret = 0; spin_lock_irqsave(&msm_iommu_lock, flags); - iommu = find_iommu_for_dev(dev); + spin_unlock_irqrestore(&msm_iommu_lock, flags); + if (iommu) iommu_device_link(&iommu->iommu, dev); else - ret = -ENODEV; - - spin_unlock_irqrestore(&msm_iommu_lock, flags); - - if (ret) - return ret; + return -ENODEV; group = iommu_group_get_for_dev(dev); if (IS_ERR(group)) @@ -425,13 +420,12 @@ static void msm_iommu_remove_device(struct device *dev) unsigned long flags; spin_lock_irqsave(&msm_iommu_lock, flags); - iommu = find_iommu_for_dev(dev); + spin_unlock_irqrestore(&msm_iommu_lock, flags); + if (iommu) iommu_device_unlink(&iommu->iommu, dev); - spin_unlock_irqrestore(&msm_iommu_lock, flags); - iommu_group_remove_device(dev); } diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index bd67e1b2c64eadf25f5b10d120cf1214b120b54f..57960cb5e04552f01b9d23cfe5e380c8e5004eb2 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -529,7 +529,7 @@ static u32 *iopte_alloc(struct omap_iommu *obj, u32 *iopgd, pte_ready: iopte = iopte_offset(iopgd, da); - *pt_dma = virt_to_phys(iopte); + *pt_dma = iopgd_page_paddr(iopgd); dev_vdbg(obj->dev, "%s: da:%08x pgd:%p *pgd:%08x pte:%p *pte:%08x\n", __func__, da, iopgd, *iopgd, iopte, *iopte); @@ -717,7 +717,7 @@ static size_t iopgtable_clear_entry_core(struct omap_iommu *obj, u32 da) } bytes *= nent; memset(iopte, 0, nent * sizeof(*iopte)); - pt_dma = virt_to_phys(iopte); + pt_dma = iopgd_page_paddr(iopgd); flush_iopte_range(obj->dev, pt_dma, pt_offset, nent); /* diff --git a/drivers/irqchip/irq-bcm7038-l1.c b/drivers/irqchip/irq-bcm7038-l1.c index 55cfb986225be79386b3d6487b953ff63ca4ab59..0b9a8b709abf892a8af5f3cf82cbde5a344f0182 100644 --- a/drivers/irqchip/irq-bcm7038-l1.c +++ b/drivers/irqchip/irq-bcm7038-l1.c @@ -217,6 +217,7 @@ static int bcm7038_l1_set_affinity(struct irq_data *d, return 0; } +#ifdef CONFIG_SMP static void bcm7038_l1_cpu_offline(struct irq_data *d) { struct cpumask *mask = irq_data_get_affinity_mask(d); @@ -241,6 +242,7 @@ static void bcm7038_l1_cpu_offline(struct irq_data *d) } irq_set_affinity_locked(d, &new_affinity, false); } +#endif static int __init bcm7038_l1_init_one(struct device_node *dn, unsigned int idx, @@ -293,7 +295,9 @@ static struct irq_chip bcm7038_l1_irq_chip = { .irq_mask = bcm7038_l1_mask, .irq_unmask = bcm7038_l1_unmask, .irq_set_affinity = bcm7038_l1_set_affinity, +#ifdef CONFIG_SMP .irq_cpu_offline = bcm7038_l1_cpu_offline, +#endif }; static int bcm7038_l1_map(struct irq_domain *d, unsigned int virq, diff --git a/drivers/irqchip/qcom/Kconfig b/drivers/irqchip/qcom/Kconfig index 5d9a9b82544f0d6bf58c4efa7972db1e70c753cd..c9ae98ba2636620ab8ac44f65b2e67acca1a3d34 100644 --- a/drivers/irqchip/qcom/Kconfig +++ b/drivers/irqchip/qcom/Kconfig @@ -31,6 +31,16 @@ config QTI_PDC_SDMMAGPIE the wakeup interrupts. Enable it when ARCH_SDMMAGPIE is selected. +config QTI_PDC_SDXPRAIRIE + bool "QTI PDC SDXPRAIRIE" + select QTI_PDC + default y if ARCH_SDXPRAIRIE + help + QTI Power Domain Controller for SDXPRAIRIE + This is used for managing and configuring + the wakeup interrupts. Enable it when + ARCH_SDXPRAIRIE is selected. + config QTI_MPM bool "QTI MPM" depends on ARCH_QCOM diff --git a/drivers/irqchip/qcom/Makefile b/drivers/irqchip/qcom/Makefile index 9ab6c8543f836bba2981519d43309730b0b4c86e..13455731eae69d9a59b590f5cf9b9a1282c7775a 100644 --- a/drivers/irqchip/qcom/Makefile +++ b/drivers/irqchip/qcom/Makefile @@ -2,5 +2,6 @@ obj-$(CONFIG_QTI_PDC) += pdc.o obj-$(CONFIG_QTI_PDC_SM8150) += pdc-sm8150.o obj-$(CONFIG_QTI_PDC_SM6150) += pdc-sm6150.o obj-$(CONFIG_QTI_PDC_SDMMAGPIE) += pdc-sdmmagpie.o +obj-$(CONFIG_QTI_PDC_SDXPRAIRIE) += pdc-sdxprairie.o obj-$(CONFIG_QTI_MPM) += mpm.o obj-$(CONFIG_QTI_MPM) += mpm.o mpm-8937.o mpm-qcs405.o diff --git a/drivers/irqchip/qcom/pdc-sdxprairie.c b/drivers/irqchip/qcom/pdc-sdxprairie.c new file mode 100644 index 0000000000000000000000000000000000000000..b89237e83e89ae980a259c9f79de503af0fc7350 --- /dev/null +++ b/drivers/irqchip/qcom/pdc-sdxprairie.c @@ -0,0 +1,78 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include "pdc.h" + +static struct pdc_pin sdxprairie_data[] = { + {0, 179}, /* rpmh_wake */ + {1, 180}, /* ee0_apps_hlos_spmi_periph_irq */ + {2, 181}, /* ee1_apps_trustzone_spmi_periph_irq */ + {3, 182}, /* secure_wdog_expired */ + {4, 183}, /* secure_wdog_bark_irq */ + {5, 184}, /* aop_wdog_expired_irq */ + {6, 185}, /* spmi_vgis_irq_to_APPS */ + {7, 186}, /* not-connected */ + {8, 187}, /* aoss_pmic_arb_mpu_xpu_summary_irq */ + {9, 188}, /* rpmh_wake */ + {10, 189}, /* eud_p1_dpse_int_mx */ + {11, 190}, /* eud_p1_dmse_int_mx */ + {12, 191}, /* pdc_apps_epcb_timeout_summary_irq */ + {13, 192}, /* spmi_protocol_irq */ + {14, 193}, /* tsense0_tsense_max_min_int */ + {15, 194}, /* not-connected */ + {16, 195}, /* tsense0_tsense_upper_lower_int */ + {17, 196}, /* not-connected */ + {18, 197}, /* tsense0_tsense_critical_int */ + {19, 198}, /* eud_int_mx[4] */ + {20, 199}, /* apps_pdc.gp_irq_mux[0] */ + {21, 200}, /* apps_pdc.gp_irq_mux[1] */ + {22, 201}, /* apps_pdc.gp_irq_mux[2] */ + {23, 202}, /* apps_pdc.gp_irq_mux[3] */ + {24, 203}, /* apps_pdc.gp_irq_mux[4] */ + {25, 204}, /* apps_pdc.gp_irq_mux[5] */ + {26, 205}, /* apps_pdc.gp_irq_mux[6] */ + {27, 206}, /* apps_pdc.gp_irq_mux[7] */ + {28, 207}, /* apps_pdc.gp_irq_mux[8] */ + {29, 208}, /* apps_pdc.gp_irq_mux[9] */ + {30, 209}, /* apps_pdc.gp_irq_mux[10] */ + {31, 210}, /* apps_pdc.gp_irq_mux[11] */ + {32, 211}, /* apps_pdc.gp_irq_mux[12] */ + {33, 212}, /* apps_pdc.gp_irq_mux[13] */ + {34, 213}, /* apps_pdc.gp_irq_mux[14] */ + {35, 214}, /* apps_pdc.gp_irq_mux[15] */ + {36, 215}, /* apps_pdc.gp_irq_mux[16] */ + {37, 216}, /* apps_pdc.gp_irq_mux[17] */ + {38, 217}, /* apps_pdc.gp_irq_mux[18] */ + {39, 218}, /* apps_pdc.gp_irq_mux[19] */ + {40, 219}, /* apps_pdc.gp_irq_mux[20] */ + {41, 220}, /* apps_pdc.gp_irq_mux[21] */ + {42, 221}, /* apps_pdc.gp_irq_mux[22] */ + {43, 222}, /* apps_pdc.gp_irq_mux[23] */ + {44, 223}, /* apps_pdc.gp_irq_mux[24] */ + {45, 224}, /* apps_pdc.gp_irq_mux[25] */ + {46, 225}, /* apps_pdc.gp_irq_mux[26] */ + {47, 226}, /* apps_pdc.gp_irq_mux[27] */ + {48, 227}, /* apps_pdc.gp_irq_mux[28] */ + {49, 228}, /* apps_pdc.gp_irq_mux[29] */ + {50, 229}, /* apps_pdc.gp_irq_mux[30] */ + {51, 230}, /* apps_pdc.gp_irq_mux[31] */ + {-1}, +}; + +static int __init qcom_pdc_gic_init(struct device_node *node, + struct device_node *parent) +{ + return qcom_pdc_init(node, parent, sdxprairie_data); +} + +IRQCHIP_DECLARE(pdc_sdxprairie, "qcom,pdc-sdxprairie", qcom_pdc_gic_init); diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index 38a5bb764c7b55cb8b742639e49756e413b4ab26..598724ffde4eaeb370c6b1ca49de027b8583fe2d 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -1640,13 +1640,7 @@ isdn_ioctl(struct file *file, uint cmd, ulong arg) } else return -EINVAL; case IIOCDBGVAR: - if (arg) { - if (copy_to_user(argp, &dev, sizeof(ulong))) - return -EFAULT; - return 0; - } else - return -EINVAL; - break; + return -EINVAL; default: if ((cmd & IIOCDRVCTL) == IIOCDRVCTL) cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK; diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c index 7b139f45f409709c49f38d1160954ff20dd9653b..2ed08a94f6d2ceb6fd5353c59b9f7b5241e6a2f2 100644 --- a/drivers/leds/leds-qpnp-flash-v2.c +++ b/drivers/leds/leds-qpnp-flash-v2.c @@ -188,6 +188,10 @@ enum strobe_type { LPG_STROBE, }; +enum wa_flags { + PM8150L_IRES_WA = BIT(0), +}; + /* * Configurations for each individual LED */ @@ -286,6 +290,7 @@ struct qpnp_flash_led { int num_snodes; int enable; int total_current_ma; + u32 wa_flags; u16 base; bool trigger_lmh; bool trigger_chgr; @@ -1028,7 +1033,12 @@ static void qpnp_flash_led_node_set(struct flash_node_data *fnode, int value) break; } } + } else if (prgm_current_ma <= 20 && + (led->wa_flags & PM8150L_IRES_WA)) { + fnode->ires_idx = FLASH_LED_IRES_BASE; + fnode->ires_ua = FLASH_LED_IRES_MIN_UA; } + fnode->current_ma = prgm_current_ma; fnode->cdev.brightness = prgm_current_ma; fnode->current_reg_val = get_current_reg_code(prgm_current_ma, @@ -1927,6 +1937,9 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, led->pdata->pmic_rev_id->pmic_subtype, led->pdata->pmic_rev_id->rev4); + if (led->pdata->pmic_rev_id->pmic_subtype == PM8150L_SUBTYPE) + led->wa_flags |= PM8150L_IRES_WA; + led->pdata->hdrm_auto_mode_en = of_property_read_bool(node, "qcom,hdrm-auto-mode"); diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c index 3f0ddc0d7393fdd477aa82578b43d37034e08e77..3fb65778e03d205df6ccd04a728d9241208ea1c0 100644 --- a/drivers/lightnvm/pblk-core.c +++ b/drivers/lightnvm/pblk-core.c @@ -190,7 +190,6 @@ void pblk_bio_free_pages(struct pblk *pblk, struct bio *bio, int off, WARN_ON(off + nr_pages != bio->bi_vcnt); - bio_advance(bio, off * PBLK_EXPOSED_PAGE_SIZE); for (i = off; i < nr_pages + off; i++) { bv = bio->bi_io_vec[i]; mempool_free(bv.bv_page, pblk->page_bio_pool); diff --git a/drivers/lightnvm/pblk-write.c b/drivers/lightnvm/pblk-write.c index 3ad9e56d2473412ae3ead5b2946066643ebd541c..d89ac573f8d838eca3401f671f558c25df19260b 100644 --- a/drivers/lightnvm/pblk-write.c +++ b/drivers/lightnvm/pblk-write.c @@ -33,6 +33,10 @@ static unsigned long pblk_end_w_bio(struct pblk *pblk, struct nvm_rq *rqd, bio_endio(original_bio); } + if (c_ctx->nr_padded) + pblk_bio_free_pages(pblk, rqd->bio, c_ctx->nr_valid, + c_ctx->nr_padded); + #ifdef CONFIG_NVM_DEBUG atomic_long_add(c_ctx->nr_valid, &pblk->sync_writes); #endif @@ -521,7 +525,8 @@ static void pblk_free_write_rqd(struct pblk *pblk, struct nvm_rq *rqd) struct bio *bio = rqd->bio; if (c_ctx->nr_padded) - pblk_bio_free_pages(pblk, bio, rqd->nr_ppas, c_ctx->nr_padded); + pblk_bio_free_pages(pblk, bio, c_ctx->nr_valid, + c_ctx->nr_padded); } static int pblk_submit_write(struct pblk *pblk) diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index c4c2b3b85ebc05f4ceea9c484f674ed40d427b42..f6e040fcad9a4936447fcecd1a49525e6a117468 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -532,8 +532,9 @@ init_pmu(void) int timeout; struct adb_request req; - out_8(&via[B], via[B] | TREQ); /* negate TREQ */ - out_8(&via[DIRB], (via[DIRB] | TREQ) & ~TACK); /* TACK in, TREQ out */ + /* Negate TREQ. Set TACK to input and TREQ to output. */ + out_8(&via[B], in_8(&via[B]) | TREQ); + out_8(&via[DIRB], (in_8(&via[DIRB]) | TREQ) & ~TACK); pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask); timeout = 100000; @@ -1455,8 +1456,8 @@ pmu_sr_intr(void) struct adb_request *req; int bite = 0; - if (via[B] & TREQ) { - printk(KERN_ERR "PMU: spurious SR intr (%x)\n", via[B]); + if (in_8(&via[B]) & TREQ) { + printk(KERN_ERR "PMU: spurious SR intr (%x)\n", in_8(&via[B])); out_8(&via[IFR], SR_INT); return NULL; } diff --git a/drivers/mailbox/mailbox-xgene-slimpro.c b/drivers/mailbox/mailbox-xgene-slimpro.c index a7040163dd43983d26071faec7ac9f815db9b799..b8b2b3533f466badbf0645efda9ea975c460c998 100644 --- a/drivers/mailbox/mailbox-xgene-slimpro.c +++ b/drivers/mailbox/mailbox-xgene-slimpro.c @@ -195,9 +195,9 @@ static int slimpro_mbox_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ctx); regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mb_base = devm_ioremap(&pdev->dev, regs->start, resource_size(regs)); - if (!mb_base) - return -ENOMEM; + mb_base = devm_ioremap_resource(&pdev->dev, regs); + if (IS_ERR(mb_base)) + return PTR_ERR(mb_base); /* Setup mailbox links */ for (i = 0; i < MBOX_CNT; i++) { diff --git a/drivers/mailbox/qcom-apcs-ipc-mailbox.c b/drivers/mailbox/qcom-apcs-ipc-mailbox.c index a297ad4c61a22515e57668b4c1d5d9819b422220..f6749ece91fa467024ff503fbca8014657983304 100644 --- a/drivers/mailbox/qcom-apcs-ipc-mailbox.c +++ b/drivers/mailbox/qcom-apcs-ipc-mailbox.c @@ -104,6 +104,8 @@ static const struct of_device_id qcom_apcs_ipc_of_match[] = { { .compatible = "qcom,msm8996-apcs-hmss-global", .data = (void *)16 }, { .compatible = "qcom,sm8150-apcs-hmss-global", .data = (void *)12 }, { .compatible = "qcom,sm8150-spcs-global", .data = (void *)0 }, + { .compatible = "qcom,sdxprairie-apcs-gcc", .data = (void *)8 }, + { .compatible = "qcom,trinket-apcs-hmss-global", .data = (void *)8 }, {} }; MODULE_DEVICE_TABLE(of, qcom_apcs_ipc_of_match); diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index 888c9020ca067a9334904ff73bb3c50170fb6879..623ff1d4396ba3aacd3f29a3851f51622348411e 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -573,6 +573,15 @@ config DM_ZONED If unsure, say N. +config DM_VERITY_AVB + tristate "Support AVB specific verity error behavior" + depends on DM_VERITY + ---help--- + Enables Android Verified Boot platform-specific error + behavior. In particular, it will modify the vbmeta partition + specified on the kernel command-line when non-transient error + occurs (followed by a panic). + config DM_ANDROID_VERITY bool "Android verity target support" depends on BLK_DEV_DM=y diff --git a/drivers/md/Makefile b/drivers/md/Makefile index bfd027659aafe63ba22adaeede557c0e600ac873..fb2e9a64378bbc1ec5a5b0599ca730b75f29966b 100644 --- a/drivers/md/Makefile +++ b/drivers/md/Makefile @@ -74,6 +74,10 @@ ifeq ($(CONFIG_DM_VERITY_FEC),y) dm-verity-objs += dm-verity-fec.o endif +ifeq ($(CONFIG_DM_VERITY_AVB),y) +dm-verity-objs += dm-verity-avb.o +endif + ifeq ($(CONFIG_DM_ANDROID_VERITY),y) dm-verity-objs += dm-android-verity.o endif diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c index 930b00f6a3a2a4b780d7c6ea166b7b36181caf22..5adb0c850b6c0800967c03f85810b74992d99c32 100644 --- a/drivers/md/bcache/writeback.c +++ b/drivers/md/bcache/writeback.c @@ -456,8 +456,10 @@ static int bch_writeback_thread(void *arg) * data on cache. BCACHE_DEV_DETACHING flag is set in * bch_cached_dev_detach(). */ - if (test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags)) + if (test_bit(BCACHE_DEV_DETACHING, &dc->disk.flags)) { + up_write(&dc->writeback_lock); break; + } } up_write(&dc->writeback_lock); diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c index 4a4e9c75fc4cddca59c30df2f18ebaa6f0baaa61..7f1c64c4ad24c9bf4c48fb6e94816a87730c5a66 100644 --- a/drivers/md/dm-cache-metadata.c +++ b/drivers/md/dm-cache-metadata.c @@ -362,7 +362,7 @@ static int __write_initial_superblock(struct dm_cache_metadata *cmd) disk_super->version = cpu_to_le32(cmd->version); memset(disk_super->policy_name, 0, sizeof(disk_super->policy_name)); memset(disk_super->policy_version, 0, sizeof(disk_super->policy_version)); - disk_super->policy_hint_size = 0; + disk_super->policy_hint_size = cpu_to_le32(0); __copy_sm_root(cmd, disk_super); @@ -700,6 +700,7 @@ static int __commit_transaction(struct dm_cache_metadata *cmd, disk_super->policy_version[0] = cpu_to_le32(cmd->policy_version[0]); disk_super->policy_version[1] = cpu_to_le32(cmd->policy_version[1]); disk_super->policy_version[2] = cpu_to_le32(cmd->policy_version[2]); + disk_super->policy_hint_size = cpu_to_le32(cmd->policy_hint_size); disk_super->read_hits = cpu_to_le32(cmd->stats.read_hits); disk_super->read_misses = cpu_to_le32(cmd->stats.read_misses); @@ -1321,6 +1322,7 @@ static int __load_mapping_v1(struct dm_cache_metadata *cmd, dm_oblock_t oblock; unsigned flags; + bool dirty = true; dm_array_cursor_get_value(mapping_cursor, (void **) &mapping_value_le); memcpy(&mapping, mapping_value_le, sizeof(mapping)); @@ -1331,8 +1333,10 @@ static int __load_mapping_v1(struct dm_cache_metadata *cmd, dm_array_cursor_get_value(hint_cursor, (void **) &hint_value_le); memcpy(&hint, hint_value_le, sizeof(hint)); } + if (cmd->clean_when_opened) + dirty = flags & M_DIRTY; - r = fn(context, oblock, to_cblock(cb), flags & M_DIRTY, + r = fn(context, oblock, to_cblock(cb), dirty, le32_to_cpu(hint), hints_valid); if (r) { DMERR("policy couldn't load cache block %llu", @@ -1360,7 +1364,7 @@ static int __load_mapping_v2(struct dm_cache_metadata *cmd, dm_oblock_t oblock; unsigned flags; - bool dirty; + bool dirty = true; dm_array_cursor_get_value(mapping_cursor, (void **) &mapping_value_le); memcpy(&mapping, mapping_value_le, sizeof(mapping)); @@ -1371,8 +1375,9 @@ static int __load_mapping_v2(struct dm_cache_metadata *cmd, dm_array_cursor_get_value(hint_cursor, (void **) &hint_value_le); memcpy(&hint, hint_value_le, sizeof(hint)); } + if (cmd->clean_when_opened) + dirty = dm_bitset_cursor_get_value(dirty_cursor); - dirty = dm_bitset_cursor_get_value(dirty_cursor); r = fn(context, oblock, to_cblock(cb), dirty, le32_to_cpu(hint), hints_valid); if (r) { @@ -1449,8 +1454,8 @@ static int __load_mappings(struct dm_cache_metadata *cmd, if (hints_valid) { r = dm_array_cursor_next(&cmd->hint_cursor); if (r) { - DMERR("dm_array_cursor_next for hint failed"); - goto out; + dm_array_cursor_end(&cmd->hint_cursor); + hints_valid = false; } } diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index 71c3507df9a0ee530c2927f1a8ac4a571d3e28fd..e2ea57d5376e8d25c3c27867b0a3033bafdfcbda 100644 --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c @@ -2330,7 +2330,7 @@ static int parse_features(struct cache_args *ca, struct dm_arg_set *as, {0, 2, "Invalid number of cache feature arguments"}, }; - int r; + int r, mode_ctr = 0; unsigned argc; const char *arg; struct cache_features *cf = &ca->features; @@ -2344,14 +2344,20 @@ static int parse_features(struct cache_args *ca, struct dm_arg_set *as, while (argc--) { arg = dm_shift_arg(as); - if (!strcasecmp(arg, "writeback")) + if (!strcasecmp(arg, "writeback")) { cf->io_mode = CM_IO_WRITEBACK; + mode_ctr++; + } - else if (!strcasecmp(arg, "writethrough")) + else if (!strcasecmp(arg, "writethrough")) { cf->io_mode = CM_IO_WRITETHROUGH; + mode_ctr++; + } - else if (!strcasecmp(arg, "passthrough")) + else if (!strcasecmp(arg, "passthrough")) { cf->io_mode = CM_IO_PASSTHROUGH; + mode_ctr++; + } else if (!strcasecmp(arg, "metadata2")) cf->metadata_version = 2; @@ -2362,6 +2368,11 @@ static int parse_features(struct cache_args *ca, struct dm_arg_set *as, } } + if (mode_ctr > 1) { + *error = "Duplicate cache io_mode features requested"; + return -EINVAL; + } + return 0; } @@ -3086,8 +3097,13 @@ static dm_cblock_t get_cache_dev_size(struct cache *cache) static bool can_resize(struct cache *cache, dm_cblock_t new_size) { - if (from_cblock(new_size) > from_cblock(cache->cache_size)) - return true; + if (from_cblock(new_size) > from_cblock(cache->cache_size)) { + if (cache->sized) { + DMERR("%s: unable to extend cache due to missing cache table reload", + cache_device_name(cache)); + return false; + } + } /* * We can't drop a dirty block when shrinking the cache. diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 98181028c7e9b4b1b3b6725d1f195c8c544bff10..eedbb31790653f3a55544533d1ce406b650fc3ea 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -3082,11 +3082,11 @@ static void crypt_io_hints(struct dm_target *ti, struct queue_limits *limits) */ limits->max_segment_size = PAGE_SIZE; - if (cc->sector_size != (1 << SECTOR_SHIFT)) { - limits->logical_block_size = cc->sector_size; - limits->physical_block_size = cc->sector_size; - blk_limits_io_min(limits, cc->sector_size); - } + limits->logical_block_size = + max_t(unsigned short, limits->logical_block_size, cc->sector_size); + limits->physical_block_size = + max_t(unsigned, limits->physical_block_size, cc->sector_size); + limits->io_min = max_t(unsigned, limits->io_min, cc->sector_size); } static struct target_type crypt_target = { diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c index cbc56372ff97b7c82337d51bfb9ca8640b0c697d..898286ed47a1004f00e7ff23f9cb29133b0f9aa3 100644 --- a/drivers/md/dm-integrity.c +++ b/drivers/md/dm-integrity.c @@ -177,7 +177,7 @@ struct dm_integrity_c { __u8 sectors_per_block; unsigned char mode; - bool suspending; + int suspending; int failed; @@ -2209,7 +2209,7 @@ static void dm_integrity_postsuspend(struct dm_target *ti) del_timer_sync(&ic->autocommit_timer); - ic->suspending = true; + WRITE_ONCE(ic->suspending, 1); queue_work(ic->commit_wq, &ic->commit_work); drain_workqueue(ic->commit_wq); @@ -2219,7 +2219,7 @@ static void dm_integrity_postsuspend(struct dm_target *ti) dm_integrity_flush_buffers(ic); } - ic->suspending = false; + WRITE_ONCE(ic->suspending, 0); BUG_ON(!RB_EMPTY_ROOT(&ic->in_progress)); diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c index cf2c67e35eafe75353e016d48efefd9aadd36291..d4b326914f0687b49bdfc83f3c30ceb60411a493 100644 --- a/drivers/md/dm-kcopyd.c +++ b/drivers/md/dm-kcopyd.c @@ -484,6 +484,8 @@ static int run_complete_job(struct kcopyd_job *job) if (atomic_dec_and_test(&kc->nr_jobs)) wake_up(&kc->destroyq); + cond_resched(); + return 0; } diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index 38a2ac24428e5b5671cb30c20a4f91d998f06597..151211b4cb1ba596465d56dfa6b556a6498e5b1a 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c @@ -3061,6 +3061,11 @@ static int raid_ctr(struct dm_target *ti, unsigned int argc, char **argv) set_bit(RT_FLAG_UPDATE_SBS, &rs->runtime_flags); rs_set_new(rs); } else if (rs_is_recovering(rs)) { + /* Rebuild particular devices */ + if (test_bit(__CTR_FLAG_REBUILD, &rs->ctr_flags)) { + set_bit(RT_FLAG_UPDATE_SBS, &rs->runtime_flags); + rs_setup_recovery(rs, MaxSector); + } /* A recovering raid set may be resized */ ; /* skip setup rs */ } else if (rs_is_reshaping(rs)) { diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c index 36ef284ad086b881324771d4f882dc6fa96d6dde..45ff8fd00248d3427ca796ce02f9002738932091 100644 --- a/drivers/md/dm-thin-metadata.c +++ b/drivers/md/dm-thin-metadata.c @@ -188,6 +188,12 @@ struct dm_pool_metadata { unsigned long flags; sector_t data_block_size; + /* + * We reserve a section of the metadata for commit overhead. + * All reported space does *not* include this. + */ + dm_block_t metadata_reserve; + /* * Set if a transaction has to be aborted but the attempt to roll back * to the previous (good) transaction failed. The only pool metadata @@ -825,6 +831,20 @@ static int __commit_transaction(struct dm_pool_metadata *pmd) return dm_tm_commit(pmd->tm, sblock); } +static void __set_metadata_reserve(struct dm_pool_metadata *pmd) +{ + int r; + dm_block_t total; + dm_block_t max_blocks = 4096; /* 16M */ + + r = dm_sm_get_nr_blocks(pmd->metadata_sm, &total); + if (r) { + DMERR("could not get size of metadata device"); + pmd->metadata_reserve = max_blocks; + } else + pmd->metadata_reserve = min(max_blocks, div_u64(total, 10)); +} + struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev, sector_t data_block_size, bool format_device) @@ -858,6 +878,8 @@ struct dm_pool_metadata *dm_pool_metadata_open(struct block_device *bdev, return ERR_PTR(r); } + __set_metadata_reserve(pmd); + return pmd; } @@ -1829,6 +1851,13 @@ int dm_pool_get_free_metadata_block_count(struct dm_pool_metadata *pmd, down_read(&pmd->root_lock); if (!pmd->fail_io) r = dm_sm_get_nr_free(pmd->metadata_sm, result); + + if (!r) { + if (*result < pmd->metadata_reserve) + *result = 0; + else + *result -= pmd->metadata_reserve; + } up_read(&pmd->root_lock); return r; @@ -1941,8 +1970,11 @@ int dm_pool_resize_metadata_dev(struct dm_pool_metadata *pmd, dm_block_t new_cou int r = -EINVAL; down_write(&pmd->root_lock); - if (!pmd->fail_io) + if (!pmd->fail_io) { r = __resize_space_map(pmd->metadata_sm, new_count); + if (!r) + __set_metadata_reserve(pmd); + } up_write(&pmd->root_lock); return r; diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 72ae5dc50532ec799b77458e7fba31d2480c23c0..699c40c7fe60878ebe184a2668b28773b02c793a 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -200,7 +200,13 @@ struct dm_thin_new_mapping; enum pool_mode { PM_WRITE, /* metadata may be changed */ PM_OUT_OF_DATA_SPACE, /* metadata may be changed, though data may not be allocated */ + + /* + * Like READ_ONLY, except may switch back to WRITE on metadata resize. Reported as READ_ONLY. + */ + PM_OUT_OF_METADATA_SPACE, PM_READ_ONLY, /* metadata may not be changed */ + PM_FAIL, /* all I/O fails */ }; @@ -1382,7 +1388,35 @@ static void set_pool_mode(struct pool *pool, enum pool_mode new_mode); static void requeue_bios(struct pool *pool); -static void check_for_space(struct pool *pool) +static bool is_read_only_pool_mode(enum pool_mode mode) +{ + return (mode == PM_OUT_OF_METADATA_SPACE || mode == PM_READ_ONLY); +} + +static bool is_read_only(struct pool *pool) +{ + return is_read_only_pool_mode(get_pool_mode(pool)); +} + +static void check_for_metadata_space(struct pool *pool) +{ + int r; + const char *ooms_reason = NULL; + dm_block_t nr_free; + + r = dm_pool_get_free_metadata_block_count(pool->pmd, &nr_free); + if (r) + ooms_reason = "Could not get free metadata blocks"; + else if (!nr_free) + ooms_reason = "No free metadata blocks"; + + if (ooms_reason && !is_read_only(pool)) { + DMERR("%s", ooms_reason); + set_pool_mode(pool, PM_OUT_OF_METADATA_SPACE); + } +} + +static void check_for_data_space(struct pool *pool) { int r; dm_block_t nr_free; @@ -1408,14 +1442,16 @@ static int commit(struct pool *pool) { int r; - if (get_pool_mode(pool) >= PM_READ_ONLY) + if (get_pool_mode(pool) >= PM_OUT_OF_METADATA_SPACE) return -EINVAL; r = dm_pool_commit_metadata(pool->pmd); if (r) metadata_operation_failed(pool, "dm_pool_commit_metadata", r); - else - check_for_space(pool); + else { + check_for_metadata_space(pool); + check_for_data_space(pool); + } return r; } @@ -1481,6 +1517,19 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result) return r; } + r = dm_pool_get_free_metadata_block_count(pool->pmd, &free_blocks); + if (r) { + metadata_operation_failed(pool, "dm_pool_get_free_metadata_block_count", r); + return r; + } + + if (!free_blocks) { + /* Let's commit before we use up the metadata reserve. */ + r = commit(pool); + if (r) + return r; + } + return 0; } @@ -1512,6 +1561,7 @@ static blk_status_t should_error_unserviceable_bio(struct pool *pool) case PM_OUT_OF_DATA_SPACE: return pool->pf.error_if_no_space ? BLK_STS_NOSPC : 0; + case PM_OUT_OF_METADATA_SPACE: case PM_READ_ONLY: case PM_FAIL: return BLK_STS_IOERR; @@ -2475,8 +2525,9 @@ static void set_pool_mode(struct pool *pool, enum pool_mode new_mode) error_retry_list(pool); break; + case PM_OUT_OF_METADATA_SPACE: case PM_READ_ONLY: - if (old_mode != new_mode) + if (!is_read_only_pool_mode(old_mode)) notify_of_pool_mode_change(pool, "read-only"); dm_pool_metadata_read_only(pool->pmd); pool->process_bio = process_bio_read_only; @@ -2514,6 +2565,8 @@ static void set_pool_mode(struct pool *pool, enum pool_mode new_mode) case PM_WRITE: if (old_mode != new_mode) notify_of_pool_mode_change(pool, "write"); + if (old_mode == PM_OUT_OF_DATA_SPACE) + cancel_delayed_work_sync(&pool->no_space_timeout); pool->out_of_data_space = false; pool->pf.error_if_no_space = pt->requested_pf.error_if_no_space; dm_pool_metadata_read_write(pool->pmd); @@ -3410,6 +3463,10 @@ static int maybe_resize_metadata_dev(struct dm_target *ti, bool *need_commit) DMINFO("%s: growing the metadata device from %llu to %llu blocks", dm_device_name(pool->pool_md), sb_metadata_dev_size, metadata_dev_size); + + if (get_pool_mode(pool) == PM_OUT_OF_METADATA_SPACE) + set_pool_mode(pool, PM_WRITE); + r = dm_pool_resize_metadata_dev(pool->pmd, metadata_dev_size); if (r) { metadata_operation_failed(pool, "dm_pool_resize_metadata_dev", r); @@ -3713,7 +3770,7 @@ static int pool_message(struct dm_target *ti, unsigned argc, char **argv) struct pool_c *pt = ti->private; struct pool *pool = pt->pool; - if (get_pool_mode(pool) >= PM_READ_ONLY) { + if (get_pool_mode(pool) >= PM_OUT_OF_METADATA_SPACE) { DMERR("%s: unable to service pool target messages in READ_ONLY or FAIL mode", dm_device_name(pool->pool_md)); return -EOPNOTSUPP; @@ -3787,6 +3844,7 @@ static void pool_status(struct dm_target *ti, status_type_t type, dm_block_t nr_blocks_data; dm_block_t nr_blocks_metadata; dm_block_t held_root; + enum pool_mode mode; char buf[BDEVNAME_SIZE]; char buf2[BDEVNAME_SIZE]; struct pool_c *pt = ti->private; @@ -3857,9 +3915,10 @@ static void pool_status(struct dm_target *ti, status_type_t type, else DMEMIT("- "); - if (pool->pf.mode == PM_OUT_OF_DATA_SPACE) + mode = get_pool_mode(pool); + if (mode == PM_OUT_OF_DATA_SPACE) DMEMIT("out_of_data_space "); - else if (pool->pf.mode == PM_READ_ONLY) + else if (is_read_only_pool_mode(mode)) DMEMIT("ro "); else DMEMIT("rw "); diff --git a/drivers/md/dm-verity-avb.c b/drivers/md/dm-verity-avb.c new file mode 100644 index 0000000000000000000000000000000000000000..a9f102aa379e9d5eb9dacf6484cacc78028a832f --- /dev/null +++ b/drivers/md/dm-verity-avb.c @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2017 Google. + * + * This file is released under the GPLv2. + * + * Based on drivers/md/dm-verity-chromeos.c + */ + +#include +#include +#include + +#define DM_MSG_PREFIX "verity-avb" + +/* Set via module parameters. */ +static char avb_vbmeta_device[64]; +static char avb_invalidate_on_error[4]; + +static void invalidate_vbmeta_endio(struct bio *bio) +{ + if (bio->bi_status) + DMERR("invalidate_vbmeta_endio: error %d", bio->bi_status); + complete(bio->bi_private); +} + +static int invalidate_vbmeta_submit(struct bio *bio, + struct block_device *bdev, + int op, int access_last_sector, + struct page *page) +{ + DECLARE_COMPLETION_ONSTACK(wait); + + bio->bi_private = &wait; + bio->bi_end_io = invalidate_vbmeta_endio; + bio_set_dev(bio, bdev); + bio_set_op_attrs(bio, op, REQ_SYNC); + + bio->bi_iter.bi_sector = 0; + if (access_last_sector) { + sector_t last_sector; + + last_sector = (i_size_read(bdev->bd_inode)>>SECTOR_SHIFT) - 1; + bio->bi_iter.bi_sector = last_sector; + } + if (!bio_add_page(bio, page, PAGE_SIZE, 0)) { + DMERR("invalidate_vbmeta_submit: bio_add_page error"); + return -EIO; + } + + submit_bio(bio); + /* Wait up to 2 seconds for completion or fail. */ + if (!wait_for_completion_timeout(&wait, msecs_to_jiffies(2000))) + return -EIO; + return 0; +} + +static int invalidate_vbmeta(dev_t vbmeta_devt) +{ + int ret = 0; + struct block_device *bdev; + struct bio *bio; + struct page *page; + fmode_t dev_mode; + /* Ensure we do synchronous unblocked I/O. We may also need + * sync_bdev() on completion, but it really shouldn't. + */ + int access_last_sector = 0; + + DMINFO("invalidate_vbmeta: acting on device %d:%d", + MAJOR(vbmeta_devt), MINOR(vbmeta_devt)); + + /* First we open the device for reading. */ + dev_mode = FMODE_READ | FMODE_EXCL; + bdev = blkdev_get_by_dev(vbmeta_devt, dev_mode, + invalidate_vbmeta); + if (IS_ERR(bdev)) { + DMERR("invalidate_kernel: could not open device for reading"); + dev_mode = 0; + ret = -ENOENT; + goto failed_to_read; + } + + bio = bio_alloc(GFP_NOIO, 1); + if (!bio) { + ret = -ENOMEM; + goto failed_bio_alloc; + } + + page = alloc_page(GFP_NOIO); + if (!page) { + ret = -ENOMEM; + goto failed_to_alloc_page; + } + + access_last_sector = 0; + ret = invalidate_vbmeta_submit(bio, bdev, REQ_OP_READ, + access_last_sector, page); + if (ret) { + DMERR("invalidate_vbmeta: error reading"); + goto failed_to_submit_read; + } + + /* We have a page. Let's make sure it looks right. */ + if (memcmp("AVB0", page_address(page), 4) == 0) { + /* Stamp it. */ + memcpy(page_address(page), "AVE0", 4); + DMINFO("invalidate_vbmeta: found vbmeta partition"); + } else { + /* Could be this is on a AVB footer, check. Also, since the + * AVB footer is in the last 64 bytes, adjust for the fact that + * we're dealing with 512-byte sectors. + */ + size_t offset = (1<bi_remaining. + */ + bio_reset(bio); + + ret = invalidate_vbmeta_submit(bio, bdev, REQ_OP_WRITE, + access_last_sector, page); + if (ret) { + DMERR("invalidate_vbmeta: error writing"); + goto failed_to_submit_write; + } + + DMERR("invalidate_vbmeta: completed."); + ret = 0; +failed_to_submit_write: +failed_to_write: +invalid_header: + __free_page(page); +failed_to_submit_read: + /* Technically, we'll leak a page with the pending bio, but + * we're about to reboot anyway. + */ +failed_to_alloc_page: + bio_put(bio); +failed_bio_alloc: + if (dev_mode) + blkdev_put(bdev, dev_mode); +failed_to_read: + return ret; +} + +void dm_verity_avb_error_handler(void) +{ + dev_t dev; + + DMINFO("AVB error handler called for %s", avb_vbmeta_device); + + if (strcmp(avb_invalidate_on_error, "yes") != 0) { + DMINFO("Not configured to invalidate"); + return; + } + + if (avb_vbmeta_device[0] == '\0') { + DMERR("avb_vbmeta_device parameter not set"); + goto fail_no_dev; + } + + dev = name_to_dev_t(avb_vbmeta_device); + if (!dev) { + DMERR("No matching partition for device: %s", + avb_vbmeta_device); + goto fail_no_dev; + } + + invalidate_vbmeta(dev); + +fail_no_dev: + ; +} + +static int __init dm_verity_avb_init(void) +{ + DMINFO("AVB error handler initialized with vbmeta device: %s", + avb_vbmeta_device); + return 0; +} + +static void __exit dm_verity_avb_exit(void) +{ +} + +module_init(dm_verity_avb_init); +module_exit(dm_verity_avb_exit); + +MODULE_AUTHOR("David Zeuthen "); +MODULE_DESCRIPTION("AVB-specific error handler for dm-verity"); +MODULE_LICENSE("GPL"); + +/* Declare parameter with no module prefix */ +#undef MODULE_PARAM_PREFIX +#define MODULE_PARAM_PREFIX "androidboot.vbmeta." +module_param_string(device, avb_vbmeta_device, sizeof(avb_vbmeta_device), 0); +module_param_string(invalidate_on_error, avb_invalidate_on_error, + sizeof(avb_invalidate_on_error), 0); diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c index 1742af24fd9cfecdfc5b11cd85df8463c9b6acbb..0227c462f3c8cc99c9ba1e7a56103af714760fe8 100644 --- a/drivers/md/dm-verity-target.c +++ b/drivers/md/dm-verity-target.c @@ -276,8 +276,12 @@ static int verity_handle_err(struct dm_verity *v, enum verity_block_type type, if (v->mode == DM_VERITY_MODE_LOGGING) return 0; - if (v->mode == DM_VERITY_MODE_RESTART) + if (v->mode == DM_VERITY_MODE_RESTART) { +#ifdef CONFIG_DM_VERITY_AVB + dm_verity_avb_error_handler(); +#endif kernel_restart("dm-verity device corrupted"); + } return 1; } diff --git a/drivers/md/dm-verity.h b/drivers/md/dm-verity.h index e80e06aa5ec6876f8dd2596c4a485157b97cd111..116e91fa50d77d1a54143913baf3749d06156ca2 100644 --- a/drivers/md/dm-verity.h +++ b/drivers/md/dm-verity.h @@ -142,4 +142,5 @@ extern void verity_io_hints(struct dm_target *ti, struct queue_limits *limits); extern void verity_dtr(struct dm_target *ti); extern int verity_ctr(struct dm_target *ti, unsigned argc, char **argv); extern int verity_map(struct dm_target *ti, struct bio *bio); +extern void dm_verity_avb_error_handler(void); #endif /* DM_VERITY_H */ diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c index 72ce0bccc86553a5ecbf6ffb59d3883f01e3dc0e..717aaffc227dfa942821bebf4133670dbc684d95 100644 --- a/drivers/md/md-cluster.c +++ b/drivers/md/md-cluster.c @@ -304,15 +304,6 @@ static void recover_bitmaps(struct md_thread *thread) while (cinfo->recovery_map) { slot = fls64((u64)cinfo->recovery_map) - 1; - /* Clear suspend_area associated with the bitmap */ - spin_lock_irq(&cinfo->suspend_lock); - list_for_each_entry_safe(s, tmp, &cinfo->suspend_list, list) - if (slot == s->slot) { - list_del(&s->list); - kfree(s); - } - spin_unlock_irq(&cinfo->suspend_lock); - snprintf(str, 64, "bitmap%04d", slot); bm_lockres = lockres_init(mddev, str, NULL, 1); if (!bm_lockres) { @@ -331,6 +322,16 @@ static void recover_bitmaps(struct md_thread *thread) pr_err("md-cluster: Could not copy data from bitmap %d\n", slot); goto clear_bit; } + + /* Clear suspend_area associated with the bitmap */ + spin_lock_irq(&cinfo->suspend_lock); + list_for_each_entry_safe(s, tmp, &cinfo->suspend_list, list) + if (slot == s->slot) { + list_del(&s->list); + kfree(s); + } + spin_unlock_irq(&cinfo->suspend_lock); + if (hi > 0) { if (lo < mddev->recovery_cp) mddev->recovery_cp = lo; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index b20c23f970f494f18d6a4b5b29de8275aef77bc8..927b60e9d3ca2d46864ee73f38e96f2d60927898 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -3754,6 +3754,13 @@ static int raid10_run(struct mddev *mddev) disk->rdev->saved_raid_disk < 0) conf->fullsync = 1; } + + if (disk->replacement && + !test_bit(In_sync, &disk->replacement->flags) && + disk->replacement->saved_raid_disk < 0) { + conf->fullsync = 1; + } + disk->recovery_disabled = mddev->recovery_disabled - 1; } @@ -4387,11 +4394,12 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, allow_barrier(conf); } + raise_barrier(conf, 0); read_more: /* Now schedule reads for blocks from sector_nr to last */ r10_bio = raid10_alloc_init_r10buf(conf); r10_bio->state = 0; - raise_barrier(conf, sectors_done != 0); + raise_barrier(conf, 1); atomic_set(&r10_bio->remaining, 0); r10_bio->mddev = mddev; r10_bio->sector = sector_nr; @@ -4487,6 +4495,8 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, if (sector_nr <= last) goto read_more; + lower_barrier(conf); + /* Now that we have done the whole section we can * update reshape_progress */ diff --git a/drivers/md/raid5-log.h b/drivers/md/raid5-log.h index 284578b0a349c7acf5d6398b19fa4196854cdff0..5c908c510c7746956f6dc56036da76ee03742765 100644 --- a/drivers/md/raid5-log.h +++ b/drivers/md/raid5-log.h @@ -43,6 +43,11 @@ extern void ppl_write_stripe_run(struct r5conf *conf); extern void ppl_stripe_write_finished(struct stripe_head *sh); extern int ppl_modify_log(struct r5conf *conf, struct md_rdev *rdev, bool add); +static inline bool raid5_has_log(struct r5conf *conf) +{ + return test_bit(MD_HAS_JOURNAL, &conf->mddev->flags); +} + static inline bool raid5_has_ppl(struct r5conf *conf) { return test_bit(MD_HAS_PPL, &conf->mddev->flags); diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 07ca2fd10189f2e68cfbf840e95305e49b98c274..dbf51b4c21b32bd037e59fcc6a46ab464cfc7ac7 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -736,7 +736,7 @@ static bool stripe_can_batch(struct stripe_head *sh) { struct r5conf *conf = sh->raid_conf; - if (conf->log || raid5_has_ppl(conf)) + if (raid5_has_log(conf) || raid5_has_ppl(conf)) return false; return test_bit(STRIPE_BATCH_READY, &sh->state) && !test_bit(STRIPE_BITMAP_PENDING, &sh->state) && @@ -4516,6 +4516,12 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) s->failed++; if (rdev && !test_bit(Faulty, &rdev->flags)) do_recovery = 1; + else if (!rdev) { + rdev = rcu_dereference( + conf->disks[i].replacement); + if (rdev && !test_bit(Faulty, &rdev->flags)) + do_recovery = 1; + } } if (test_bit(R5_InJournal, &dev->flags)) @@ -7711,7 +7717,7 @@ static int raid5_resize(struct mddev *mddev, sector_t sectors) sector_t newsize; struct r5conf *conf = mddev->private; - if (conf->log || raid5_has_ppl(conf)) + if (raid5_has_log(conf) || raid5_has_ppl(conf)) return -EINVAL; sectors &= ~((sector_t)conf->chunk_sectors - 1); newsize = raid5_size(mddev, sectors, mddev->raid_disks); @@ -7762,7 +7768,7 @@ static int check_reshape(struct mddev *mddev) { struct r5conf *conf = mddev->private; - if (conf->log || raid5_has_ppl(conf)) + if (raid5_has_log(conf) || raid5_has_ppl(conf)) return -EINVAL; if (mddev->delta_disks == 0 && mddev->new_layout == mddev->layout && diff --git a/drivers/media/dvb-frontends/helene.c b/drivers/media/dvb-frontends/helene.c index 2ab8d83e55768310ed826f3e4e36d07042070633..fcfe658a43288d418c5f56948f19ddd7088fe5da 100644 --- a/drivers/media/dvb-frontends/helene.c +++ b/drivers/media/dvb-frontends/helene.c @@ -897,7 +897,10 @@ static int helene_x_pon(struct helene_priv *priv) helene_write_regs(priv, 0x99, cdata, sizeof(cdata)); /* 0x81 - 0x94 */ - data[0] = 0x18; /* xtal 24 MHz */ + if (priv->xtal == SONY_HELENE_XTAL_16000) + data[0] = 0x10; /* xtal 16 MHz */ + else + data[0] = 0x18; /* xtal 24 MHz */ data[1] = (uint8_t)(0x80 | (0x04 & 0x1F)); /* 4 x 25 = 100uA */ data[2] = (uint8_t)(0x80 | (0x26 & 0x7F)); /* 38 x 0.25 = 9.5pF */ data[3] = 0x80; /* REFOUT signal output 500mVpp */ diff --git a/drivers/media/i2c/ov5645.c b/drivers/media/i2c/ov5645.c index a31fe18c71d6d7c7fd9278fdde6113c233e08856..2d96c184975936be0de8e2b3e9b7a0e8f9641104 100644 --- a/drivers/media/i2c/ov5645.c +++ b/drivers/media/i2c/ov5645.c @@ -510,8 +510,8 @@ static const struct reg_value ov5645_setting_full[] = { }; static const s64 link_freq[] = { - 222880000, - 334320000 + 224000000, + 336000000 }; static const struct ov5645_mode_info ov5645_mode_info_data[] = { @@ -520,7 +520,7 @@ static const struct ov5645_mode_info ov5645_mode_info_data[] = { .height = 960, .data = ov5645_setting_sxga, .data_size = ARRAY_SIZE(ov5645_setting_sxga), - .pixel_clock = 111440000, + .pixel_clock = 112000000, .link_freq = 0 /* an index in link_freq[] */ }, { @@ -528,7 +528,7 @@ static const struct ov5645_mode_info ov5645_mode_info_data[] = { .height = 1080, .data = ov5645_setting_1080p, .data_size = ARRAY_SIZE(ov5645_setting_1080p), - .pixel_clock = 167160000, + .pixel_clock = 168000000, .link_freq = 1 /* an index in link_freq[] */ }, { @@ -536,7 +536,7 @@ static const struct ov5645_mode_info ov5645_mode_info_data[] = { .height = 1944, .data = ov5645_setting_full, .data_size = ARRAY_SIZE(ov5645_setting_full), - .pixel_clock = 167160000, + .pixel_clock = 168000000, .link_freq = 1 /* an index in link_freq[] */ }, }; @@ -1157,7 +1157,8 @@ static int ov5645_probe(struct i2c_client *client, return ret; } - if (xclk_freq != 23880000) { + /* external clock must be 24MHz, allow 1% tolerance */ + if (xclk_freq < 23760000 || xclk_freq > 24240000) { dev_err(dev, "external clock frequency %u is not supported\n", xclk_freq); return -EINVAL; diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c index 806383500313e029bcf9bbb14cdbac0f55fcefff..14377af7c888898b2c19e969c2475fe558ebdac3 100644 --- a/drivers/media/i2c/soc_camera/ov772x.c +++ b/drivers/media/i2c/soc_camera/ov772x.c @@ -834,7 +834,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, * set COM8 */ if (priv->band_filter) { - ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, 1); + ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, BNDF_ON_OFF); if (!ret) ret = ov772x_mask_set(client, BDBASE, 0xff, 256 - priv->band_filter); diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 698fa764999c7a0dab55e13ef1cf363c19f45a67..59b0c1fce9be70e7fdc00dd8dfee8d45ef2a2b05 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -871,7 +871,7 @@ static int tvp5150_fill_fmt(struct v4l2_subdev *sd, f = &format->format; f->width = decoder->rect.width; - f->height = decoder->rect.height; + f->height = decoder->rect.height / 2; f->code = MEDIA_BUS_FMT_UYVY8_2X8; f->field = V4L2_FIELD_ALTERNATE; diff --git a/drivers/media/pci/tw686x/tw686x-video.c b/drivers/media/pci/tw686x/tw686x-video.c index 0ea8dd44026c34e6772b35c391aa03d15aefeffd..3a06c000f97bbf629c8539002cddb7d869baa850 100644 --- a/drivers/media/pci/tw686x/tw686x-video.c +++ b/drivers/media/pci/tw686x/tw686x-video.c @@ -1190,6 +1190,14 @@ int tw686x_video_init(struct tw686x_dev *dev) return err; } + /* Initialize vc->dev and vc->ch for the error path */ + for (ch = 0; ch < max_channels(dev); ch++) { + struct tw686x_video_channel *vc = &dev->video_channels[ch]; + + vc->dev = dev; + vc->ch = ch; + } + for (ch = 0; ch < max_channels(dev); ch++) { struct tw686x_video_channel *vc = &dev->video_channels[ch]; struct video_device *vdev; @@ -1198,9 +1206,6 @@ int tw686x_video_init(struct tw686x_dev *dev) spin_lock_init(&vc->qlock); INIT_LIST_HEAD(&vc->vidq_queued); - vc->dev = dev; - vc->ch = ch; - /* default settings */ err = tw686x_set_standard(vc, V4L2_STD_NTSC); if (err) diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index 56fe4e5b396e1a068ba601deeabe02af053e678c..4a65861433d6862cf0c7e8775e5d71658ecee3fb 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -1114,6 +1114,14 @@ static int initialize_vpif(void) return err; } +static void free_vpif_objs(void) +{ + int i; + + for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) + kfree(vpif_obj.dev[i]); +} + static int vpif_async_bound(struct v4l2_async_notifier *notifier, struct v4l2_subdev *subdev, struct v4l2_async_subdev *asd) @@ -1250,11 +1258,6 @@ static __init int vpif_probe(struct platform_device *pdev) return -EINVAL; } - if (!pdev->dev.platform_data) { - dev_warn(&pdev->dev, "Missing platform data. Giving up.\n"); - return -EINVAL; - } - vpif_dev = &pdev->dev; err = initialize_vpif(); @@ -1266,7 +1269,7 @@ static __init int vpif_probe(struct platform_device *pdev) err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev); if (err) { v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n"); - return err; + goto vpif_free; } while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, res_idx))) { @@ -1309,7 +1312,10 @@ static __init int vpif_probe(struct platform_device *pdev) if (vpif_obj.sd[i]) vpif_obj.sd[i]->grp_id = 1 << i; } - vpif_probe_complete(); + err = vpif_probe_complete(); + if (err) { + goto probe_subdev_out; + } } else { vpif_obj.notifier.subdevs = vpif_obj.config->asd; vpif_obj.notifier.num_subdevs = vpif_obj.config->asd_sizes[0]; @@ -1330,6 +1336,8 @@ static __init int vpif_probe(struct platform_device *pdev) kfree(vpif_obj.sd); vpif_unregister: v4l2_device_unregister(&vpif_obj.v4l2_dev); +vpif_free: + free_vpif_objs(); return err; } @@ -1351,8 +1359,8 @@ static int vpif_remove(struct platform_device *device) ch = vpif_obj.dev[i]; /* Unregister video device */ video_unregister_device(&ch->video_dev); - kfree(vpif_obj.dev[i]); } + free_vpif_objs(); return 0; } diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.c b/drivers/media/platform/exynos4-is/fimc-isp-video.c index 55ba696b8cf40e13339e42234bfd352e8df90520..a920164f53f1f0ab9de8a9947af72ac6cf653c95 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp-video.c +++ b/drivers/media/platform/exynos4-is/fimc-isp-video.c @@ -384,12 +384,17 @@ static void __isp_video_try_fmt(struct fimc_isp *isp, struct v4l2_pix_format_mplane *pixm, const struct fimc_fmt **fmt) { - *fmt = fimc_isp_find_format(&pixm->pixelformat, NULL, 2); + const struct fimc_fmt *__fmt; + + __fmt = fimc_isp_find_format(&pixm->pixelformat, NULL, 2); + + if (fmt) + *fmt = __fmt; pixm->colorspace = V4L2_COLORSPACE_SRGB; pixm->field = V4L2_FIELD_NONE; - pixm->num_planes = (*fmt)->memplanes; - pixm->pixelformat = (*fmt)->fourcc; + pixm->num_planes = __fmt->memplanes; + pixm->pixelformat = __fmt->fourcc; /* * TODO: double check with the docmentation these width/height * constraints are correct. diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c index fb43025df57379834a99e1be3d6124c827cd91a9..254d696dffd89058449083df4ed8652696dde24d 100644 --- a/drivers/media/platform/fsl-viu.c +++ b/drivers/media/platform/fsl-viu.c @@ -1417,7 +1417,7 @@ static int viu_of_probe(struct platform_device *op) sizeof(struct viu_reg), DRV_NAME)) { dev_err(&op->dev, "Error while requesting mem region\n"); ret = -EBUSY; - goto err; + goto err_irq; } /* remap registers */ @@ -1425,7 +1425,7 @@ static int viu_of_probe(struct platform_device *op) if (!viu_regs) { dev_err(&op->dev, "Can't map register set\n"); ret = -ENOMEM; - goto err; + goto err_irq; } /* Prepare our private structure */ @@ -1433,7 +1433,7 @@ static int viu_of_probe(struct platform_device *op) if (!viu_dev) { dev_err(&op->dev, "Can't allocate private structure\n"); ret = -ENOMEM; - goto err; + goto err_irq; } viu_dev->vr = viu_regs; @@ -1449,16 +1449,21 @@ static int viu_of_probe(struct platform_device *op) ret = v4l2_device_register(viu_dev->dev, &viu_dev->v4l2_dev); if (ret < 0) { dev_err(&op->dev, "v4l2_device_register() failed: %d\n", ret); - goto err; + goto err_irq; } ad = i2c_get_adapter(0); + if (!ad) { + ret = -EFAULT; + dev_err(&op->dev, "couldn't get i2c adapter\n"); + goto err_v4l2; + } v4l2_ctrl_handler_init(&viu_dev->hdl, 5); if (viu_dev->hdl.error) { ret = viu_dev->hdl.error; dev_err(&op->dev, "couldn't register control\n"); - goto err_vdev; + goto err_i2c; } /* This control handler will inherit the control(s) from the sub-device(s). */ @@ -1475,7 +1480,7 @@ static int viu_of_probe(struct platform_device *op) vdev = video_device_alloc(); if (vdev == NULL) { ret = -ENOMEM; - goto err_vdev; + goto err_hdl; } *vdev = viu_template; @@ -1496,7 +1501,7 @@ static int viu_of_probe(struct platform_device *op) ret = video_register_device(viu_dev->vdev, VFL_TYPE_GRABBER, -1); if (ret < 0) { video_device_release(viu_dev->vdev); - goto err_vdev; + goto err_unlock; } /* enable VIU clock */ @@ -1504,12 +1509,12 @@ static int viu_of_probe(struct platform_device *op) if (IS_ERR(clk)) { dev_err(&op->dev, "failed to lookup the clock!\n"); ret = PTR_ERR(clk); - goto err_clk; + goto err_vdev; } ret = clk_prepare_enable(clk); if (ret) { dev_err(&op->dev, "failed to enable the clock!\n"); - goto err_clk; + goto err_vdev; } viu_dev->clk = clk; @@ -1520,7 +1525,7 @@ static int viu_of_probe(struct platform_device *op) if (request_irq(viu_dev->irq, viu_intr, 0, "viu", (void *)viu_dev)) { dev_err(&op->dev, "Request VIU IRQ failed.\n"); ret = -ENODEV; - goto err_irq; + goto err_clk; } mutex_unlock(&viu_dev->lock); @@ -1528,16 +1533,19 @@ static int viu_of_probe(struct platform_device *op) dev_info(&op->dev, "Freescale VIU Video Capture Board\n"); return ret; -err_irq: - clk_disable_unprepare(viu_dev->clk); err_clk: - video_unregister_device(viu_dev->vdev); + clk_disable_unprepare(viu_dev->clk); err_vdev: - v4l2_ctrl_handler_free(&viu_dev->hdl); + video_unregister_device(viu_dev->vdev); +err_unlock: mutex_unlock(&viu_dev->lock); +err_hdl: + v4l2_ctrl_handler_free(&viu_dev->hdl); +err_i2c: i2c_put_adapter(ad); +err_v4l2: v4l2_device_unregister(&viu_dev->v4l2_dev); -err: +err_irq: irq_dispose_mapping(viu_irq); return ret; } diff --git a/drivers/media/platform/msm/npu/npu_common.h b/drivers/media/platform/msm/npu/npu_common.h index 76ef0c5ba638ff81512f4690d71e97c73e68f8a6..fd142099c3bb1af763f8f416c96a057ba61a2f51 100644 --- a/drivers/media/platform/msm/npu/npu_common.h +++ b/drivers/media/platform/msm/npu/npu_common.h @@ -28,6 +28,7 @@ #include #include #include +#include #include "npu_mgr.h" @@ -47,6 +48,7 @@ #define NPU_MAX_REGULATOR_NUM 2 #define NPU_MAX_DT_NAME_LEN 21 #define NPU_MAX_PWRLEVELS 8 +#define NPU_MAX_STATS_BUF_SIZE 16384 /* ------------------------------------------------------------------------- * Data Structures @@ -197,7 +199,7 @@ struct npu_device { struct npu_smmu_ctx smmu_ctx; struct npu_debugfs_ctx debugfs_ctx; - struct npu_mbox mbox[NPU_MAX_MBOX_NUM]; + struct npu_mbox mbox_aop; struct thermal_cooling_device *tcdev; struct npu_pwrctrl pwrctrl; diff --git a/drivers/media/platform/msm/npu/npu_dev.c b/drivers/media/platform/msm/npu/npu_dev.c index 51ee0aff561c9a90824a8ba02aaa9de300d44606..1a44fd251d8748618e720d94ade7b5e4672bd1ff 100644 --- a/drivers/media/platform/msm/npu/npu_dev.c +++ b/drivers/media/platform/msm/npu/npu_dev.c @@ -40,6 +40,7 @@ #define DDR_MAPPED_SIZE 0x60000000 #define PERF_MODE_DEFAULT 0 +#define MBOX_OP_TIMEOUTMS 1000 /* ------------------------------------------------------------------------- * File Scope Prototypes @@ -956,7 +957,7 @@ static int npu_load_network(struct npu_client *client, ret = npu_host_load_network(client, &req); if (ret) { - pr_err("network load failed: %d\n", ret); + pr_err("npu_host_load_network failed %d\n", ret); return ret; } @@ -1013,7 +1014,7 @@ static int npu_load_network_v2(struct npu_client *client, kfree(patch_info); if (ret) { - pr_err("network load failed: %d\n", ret); + pr_err("npu_host_load_network_v2 failed %d\n", ret); return ret; } @@ -1045,7 +1046,7 @@ static int npu_unload_network(struct npu_client *client, ret = npu_host_unload_network(client, &req); if (ret) { - pr_err("npu_host_unload_network failed\n"); + pr_err("npu_host_unload_network failed %d\n", ret); return ret; } @@ -1083,7 +1084,7 @@ static int npu_exec_network(struct npu_client *client, ret = npu_host_exec_network(client, &req); if (ret) { - pr_err("npu_host_exec_network failed\n"); + pr_err("npu_host_exec_network failed %d\n", ret); return ret; } @@ -1116,9 +1117,9 @@ static int npu_exec_network_v2(struct npu_client *client, return -EINVAL; } - if (req.stats_buf_size > MSM_NPU_MAX_STATS_BUF_SIZE) { + if (req.stats_buf_size > NPU_MAX_STATS_BUF_SIZE) { pr_err("Invalid stats buffer size %d max %d\n", - req.stats_buf_size, MSM_NPU_MAX_STATS_BUF_SIZE); + req.stats_buf_size, NPU_MAX_STATS_BUF_SIZE); return -EINVAL; } @@ -1142,7 +1143,7 @@ static int npu_exec_network_v2(struct npu_client *client, kfree(patch_buf_info); if (ret) { - pr_err("npu_host_exec_network failed\n"); + pr_err("npu_host_exec_network_v2 failed %d\n", ret); return ret; } @@ -1524,6 +1525,27 @@ static int npu_irq_init(struct npu_device *npu_dev) return ret; } +static int npu_mbox_init(struct npu_device *npu_dev) +{ + struct platform_device *pdev = npu_dev->pdev; + struct npu_mbox *mbox_aop = &npu_dev->mbox_aop; + + if (of_find_property(pdev->dev.of_node, "mboxes", NULL)) { + mbox_aop->client.dev = &pdev->dev; + mbox_aop->client.tx_block = true; + mbox_aop->client.tx_tout = MBOX_OP_TIMEOUTMS; + mbox_aop->client.knows_txdone = false; + + mbox_aop->chan = mbox_request_channel(&mbox_aop->client, 0); + if (IS_ERR(mbox_aop->chan)) { + pr_warn("mailbox channel request failed\n"); + mbox_aop->chan = NULL; + } + } + + return 0; +} + /* ------------------------------------------------------------------------- * Probe/Remove * ------------------------------------------------------------------------- @@ -1572,6 +1594,10 @@ static int npu_probe(struct platform_device *pdev) if (rc) goto error_get_dev_num; + rc = npu_mbox_init(npu_dev); + if (rc) + goto error_get_dev_num; + npu_dev->npu_base = devm_ioremap(&pdev->dev, res->start, npu_dev->reg_size); if (unlikely(!npu_dev->npu_base)) { @@ -1680,6 +1706,8 @@ static int npu_probe(struct platform_device *pdev) class_destroy(npu_dev->class); error_class_create: unregister_chrdev_region(npu_dev->dev_num, 1); + if (npu_dev->mbox_aop.chan) + mbox_free_channel(npu_dev->mbox_aop.chan); error_get_dev_num: return rc; } @@ -1700,6 +1728,9 @@ static int npu_remove(struct platform_device *pdev) class_destroy(npu_dev->class); unregister_chrdev_region(npu_dev->dev_num, 1); platform_set_drvdata(pdev, NULL); + if (npu_dev->mbox_aop.chan) + mbox_free_channel(npu_dev->mbox_aop.chan); + return 0; } diff --git a/drivers/media/platform/msm/npu/npu_host_ipc.c b/drivers/media/platform/msm/npu/npu_host_ipc.c index 0730e2019edca11eeabbee2ccc86165d70a99e44..ac2c28981e7f16d0d2d672791554085b4915ca75 100644 --- a/drivers/media/platform/msm/npu/npu_host_ipc.c +++ b/drivers/media/platform/msm/npu/npu_host_ipc.c @@ -156,15 +156,17 @@ static int npu_host_ipc_send_cmd_hfi(struct npu_device *npu_dev, { int status = 0; uint8_t is_rx_req_set = 0; + uint32_t retry_cnt = 5; status = ipc_queue_write(npu_dev, q_idx, (uint8_t *)cmd_ptr, &is_rx_req_set); if (status == -ENOSPC) { - while (status == -ENOSPC) { + do { + msleep(20); status = ipc_queue_write(npu_dev, q_idx, (uint8_t *)cmd_ptr, &is_rx_req_set); - } + } while ((status == -ENOSPC) && (--retry_cnt > 0)); } if (status == 0) { diff --git a/drivers/media/platform/msm/npu/npu_mgr.c b/drivers/media/platform/msm/npu/npu_mgr.c index 51193d13fd68281b0eab812d5939c3c5a35cf92e..d684ae47294ee4231cb75a027c4e6f29cc3148cd 100644 --- a/drivers/media/platform/msm/npu/npu_mgr.c +++ b/drivers/media/platform/msm/npu/npu_mgr.c @@ -46,21 +46,25 @@ static int wait_for_status_ready(struct npu_device *npu_dev, static struct npu_network *alloc_network(struct npu_host_ctx *ctx, struct npu_client *client); static struct npu_network *get_network_by_hdl(struct npu_host_ctx *ctx, - uint32_t hdl); + struct npu_client *client, uint32_t hdl); static struct npu_network *get_network_by_id(struct npu_host_ctx *ctx, + struct npu_client *client, int64_t id); +static void free_network(struct npu_host_ctx *ctx, struct npu_client *client, int64_t id); -static void free_network(struct npu_host_ctx *ctx, int64_t id); +static int network_get(struct npu_network *network); +static int network_put(struct npu_network *network); static void app_msg_proc(struct npu_host_ctx *host_ctx, uint32_t *msg); static void log_msg_proc(struct npu_device *npu_dev, uint32_t *msg); static void host_session_msg_hdlr(struct npu_device *npu_dev); static void host_session_log_hdlr(struct npu_device *npu_dev); -static int host_error_hdlr(struct npu_device *npu_dev); +static int host_error_hdlr(struct npu_device *npu_dev, bool force); static int npu_send_network_cmd(struct npu_device *npu_dev, struct npu_network *network, void *cmd_ptr, bool async); static int npu_send_misc_cmd(struct npu_device *npu_dev, uint32_t q_idx, void *cmd_ptr); static int npu_queue_event(struct npu_client *client, struct npu_kevent *evt); static int npu_notify_dsp(struct npu_device *npu_dev, bool pwr_up); +static int npu_notify_aop(struct npu_device *npu_dev, bool on); /* ------------------------------------------------------------------------- * Function Definitions - Init / Deinit @@ -78,6 +82,8 @@ int fw_init(struct npu_device *npu_dev) return 0; } + npu_notify_aop(npu_dev, true); + if (npu_enable_core_power(npu_dev)) { ret = -EPERM; goto enable_pw_fail; @@ -263,6 +269,8 @@ void fw_deinit(struct npu_device *npu_dev, bool ssr) complete(&host_ctx->fw_deinit_done); mutex_unlock(&host_ctx->lock); pr_debug("firmware deinit complete\n"); + npu_notify_aop(npu_dev, false); + return; } @@ -317,14 +325,15 @@ irqreturn_t npu_intr_hdler(int irq, void *ptr) * Function Definitions - Control * ------------------------------------------------------------------------- */ -static int host_error_hdlr(struct npu_device *npu_dev) +static int host_error_hdlr(struct npu_device *npu_dev, bool force) { struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; struct npu_network *network = NULL; struct npu_kevent kevt; int i; - if ((host_ctx->wdg_irq_sts == 0) && (host_ctx->err_irq_sts == 0)) + if ((host_ctx->wdg_irq_sts == 0) && (host_ctx->err_irq_sts == 0) + && !force) return 0; if (host_ctx->wdg_irq_sts) @@ -335,6 +344,7 @@ static int host_error_hdlr(struct npu_device *npu_dev) host_ctx->err_irq_sts = 0; /* flush all pending npu cmds */ + mutex_lock(&host_ctx->lock); for (i = 0; i < MAX_LOADED_NETWORK; i++) { network = &host_ctx->networks[i]; if (network->is_valid && network->cmd_pending && @@ -353,6 +363,7 @@ static int host_error_hdlr(struct npu_device *npu_dev) } } complete_all(&host_ctx->loopback_done); + mutex_unlock(&host_ctx->lock); return 1; } @@ -365,7 +376,7 @@ static void host_irq_wq(struct work_struct *work) host_ctx = container_of(work, struct npu_host_ctx, irq_work); npu_dev = container_of(host_ctx, struct npu_device, host_ctx); - if (host_error_hdlr(npu_dev)) + if (host_error_hdlr(npu_dev, false)) return; host_session_log_hdlr(npu_dev); @@ -447,90 +458,165 @@ static int npu_notify_dsp(struct npu_device *npu_dev, bool pwr_up) return ret; } +#define MAX_LEN 128 + +static int npu_notify_aop(struct npu_device *npu_dev, bool on) +{ + char buf[MAX_LEN]; + struct qmp_pkt pkt; + int buf_size, rc = 0; + + if (!npu_dev->mbox_aop.chan) { + pr_warn("aop mailbox channel is not available\n"); + return 0; + } + + buf_size = snprintf(buf, MAX_LEN, "{class: bcm, res: npu_on, val: %d}", + on ? 1 : 0); + if (buf_size < 0) { + pr_err("prepare qmp notify buf failed\n"); + return -EINVAL; + } + + pr_debug("send msg %s to aop\n", buf); + memset(&pkt, 0, sizeof(pkt)); + pkt.size = (buf_size + 3) & ~0x3; + pkt.data = buf; + + rc = mbox_send_message(npu_dev->mbox_aop.chan, &pkt); + if (rc < 0) + pr_err("qmp message send failed, ret=%d\n", rc); + + return rc; +} + /* ------------------------------------------------------------------------- * Function Definitions - Network Management * ------------------------------------------------------------------------- */ +static int network_put(struct npu_network *network) +{ + if (!network) + return 0; + + return atomic_dec_return(&network->ref_cnt); +} + +static int network_get(struct npu_network *network) +{ + if (!network) + return 0; + + return atomic_inc_return(&network->ref_cnt); +} + static struct npu_network *alloc_network(struct npu_host_ctx *ctx, struct npu_client *client) { int32_t i; struct npu_network *network = ctx->networks; - mutex_lock(&ctx->lock); + WARN_ON(!mutex_is_locked(&ctx->lock)); + for (i = 0; i < MAX_LOADED_NETWORK; i++) { - if (network->id == 0) { - network->id = i + 1; - network->network_hdl = 0; + if (network->id == 0) break; - } + network++; } - if (i >= MAX_LOADED_NETWORK) - network = NULL; - else - ctx->network_num++; - mutex_unlock(&ctx->lock); - if (network) { - init_completion(&network->cmd_done); - network->is_valid = true; - network->fw_error = false; - network->cmd_pending = false; - network->client = client; - network->stats_buf = kzalloc(MSM_NPU_MAX_STATS_BUF_SIZE, - GFP_KERNEL); - if (!network->stats_buf) { - free_network(ctx, network->id); - network = NULL; - } + if (i == MAX_LOADED_NETWORK) { + pr_err("No free network\n"); + return NULL; + } + + memset(network, 0, sizeof(struct npu_network)); + network->id = i + 1; + init_completion(&network->cmd_done); + network->is_valid = true; + network->client = client; + network->stats_buf = kzalloc(NPU_MAX_STATS_BUF_SIZE, + GFP_KERNEL); + if (!network->stats_buf) { + memset(network, 0, sizeof(struct npu_network)); + return NULL; } + ctx->network_num++; return network; } static struct npu_network *get_network_by_hdl(struct npu_host_ctx *ctx, - uint32_t hdl) + struct npu_client *client, uint32_t hdl) { int32_t i; struct npu_network *network = ctx->networks; + WARN_ON(!mutex_is_locked(&ctx->lock)); + for (i = 0; i < MAX_LOADED_NETWORK; i++) { if (network->network_hdl == hdl) break; network++; } + if ((i == MAX_LOADED_NETWORK) || !network->is_valid) { pr_err("network hdl invalid %d\n", hdl); - network = NULL; + return NULL; + } + + if (client && (client != network->client)) { + pr_err("network %d doesn't belong to this client\n", + network->id); + return NULL; } + network_get(network); return network; } static struct npu_network *get_network_by_id(struct npu_host_ctx *ctx, - int64_t id) + struct npu_client *client, int64_t id) { + struct npu_network *network = NULL; + + WARN_ON(!mutex_is_locked(&ctx->lock)); + if (id < 1 || id > MAX_LOADED_NETWORK || !ctx->networks[id - 1].is_valid) { - pr_err("network id invalid %d\n", (int32_t)id); + pr_err("Invalid network id %d\n", (int32_t)id); return NULL; } - return &ctx->networks[id - 1]; + network = &ctx->networks[id - 1]; + if (client && (client != network->client)) { + pr_err("network %d doesn't belong to this client\n", id); + return NULL; + } + + network_get(network); + return network; } -static void free_network(struct npu_host_ctx *ctx, int64_t id) +static void free_network(struct npu_host_ctx *ctx, struct npu_client *client, + int64_t id) { - struct npu_network *network = get_network_by_id(ctx, id); + struct npu_network *network = NULL; + WARN_ON(!mutex_is_locked(&ctx->lock)); + + network = get_network_by_id(ctx, client, id); if (network) { - kfree(network->stats_buf); - mutex_lock(&ctx->lock); - memset(network, 0, sizeof(struct npu_network)); - ctx->network_num--; - mutex_unlock(&ctx->lock); + network_put(network); + if (atomic_read(&network->ref_cnt) == 0) { + kfree(network->stats_buf); + memset(network, 0, sizeof(struct npu_network)); + ctx->network_num--; + } else { + pr_warn("network %d:%d is in use\n", network->id, + atomic_read(&network->ref_cnt)); + } } } @@ -580,7 +666,7 @@ static void app_msg_proc(struct npu_host_ctx *host_ctx, uint32_t *msg) pr_debug("total_num_layers: %d\n", exe_rsp_pkt->stats.exe_stats.total_num_layers); - network = get_network_by_hdl(host_ctx, + network = get_network_by_hdl(host_ctx, NULL, exe_rsp_pkt->network_hdl); if (!network) { pr_err("can't find network %x\n", @@ -588,6 +674,14 @@ static void app_msg_proc(struct npu_host_ctx *host_ctx, uint32_t *msg) break; } + if (network->trans_id != exe_rsp_pkt->header.trans_id) { + pr_err("execute_pkt trans_id is not match %d:%d\n", + network->trans_id, + exe_rsp_pkt->header.trans_id); + network_put(network); + break; + } + network->cmd_pending = false; network->cmd_ret_status = exe_rsp_pkt->header.status; @@ -603,6 +697,7 @@ static void app_msg_proc(struct npu_host_ctx *host_ctx, uint32_t *msg) if (npu_queue_event(network->client, &kevt)) pr_err("queue npu event failed\n"); } + network_put(network); break; } @@ -616,7 +711,7 @@ static void app_msg_proc(struct npu_host_ctx *host_ctx, uint32_t *msg) exe_rsp_pkt->header.status); pr_debug("trans_id : %d", exe_rsp_pkt->header.trans_id); - network = get_network_by_hdl(host_ctx, + network = get_network_by_hdl(host_ctx, NULL, exe_rsp_pkt->network_hdl); if (!network) { pr_err("can't find network %x\n", @@ -624,6 +719,14 @@ static void app_msg_proc(struct npu_host_ctx *host_ctx, uint32_t *msg) break; } + if (network->trans_id != exe_rsp_pkt->header.trans_id) { + pr_err("execute_pkt_v2 trans_id is not match %d:%d\n", + network->trans_id, + exe_rsp_pkt->header.trans_id); + network_put(network); + break; + } + pr_debug("network id : %d", network->id); stats_size = exe_rsp_pkt->header.size - sizeof(*exe_rsp_pkt); pr_debug("stats_size %d:%d\n", exe_rsp_pkt->header.size, @@ -653,6 +756,7 @@ static void app_msg_proc(struct npu_host_ctx *host_ctx, uint32_t *msg) } else { complete(&network->cmd_done); } + network_put(network); break; } case NPU_IPC_MSG_LOAD_DONE: @@ -671,16 +775,26 @@ static void app_msg_proc(struct npu_host_ctx *host_ctx, uint32_t *msg) */ pr_debug("network_hdl: %x\n", load_rsp_pkt->network_hdl); network_id = load_rsp_pkt->network_hdl >> 16; - network = get_network_by_id(host_ctx, network_id); + network = get_network_by_id(host_ctx, NULL, network_id); if (!network) { pr_err("can't find network %d\n", network_id); break; } + + if (network->trans_id != load_rsp_pkt->header.trans_id) { + pr_err("load_rsp_pkt trans_id is not match %d:%d\n", + network->trans_id, + load_rsp_pkt->header.trans_id); + network_put(network); + break; + } + network->network_hdl = load_rsp_pkt->network_hdl; network->cmd_pending = false; network->cmd_ret_status = load_rsp_pkt->header.status; complete(&network->cmd_done); + network_put(network); break; } case NPU_IPC_MSG_UNLOAD_DONE: @@ -692,7 +806,7 @@ static void app_msg_proc(struct npu_host_ctx *host_ctx, uint32_t *msg) unload_rsp_pkt->header.status, unload_rsp_pkt->header.trans_id); - network = get_network_by_hdl(host_ctx, + network = get_network_by_hdl(host_ctx, NULL, unload_rsp_pkt->network_hdl); if (!network) { pr_err("can't find network %x\n", @@ -700,10 +814,19 @@ static void app_msg_proc(struct npu_host_ctx *host_ctx, uint32_t *msg) break; } + if (network->trans_id != unload_rsp_pkt->header.trans_id) { + pr_err("unload_rsp_pkt trans_id is not match %d:%d\n", + network->trans_id, + unload_rsp_pkt->header.trans_id); + network_put(network); + break; + } + network->cmd_pending = false; network->cmd_ret_status = unload_rsp_pkt->header.status; complete(&network->cmd_done); + network_put(network); break; } case NPU_IPC_MSG_LOOPBACK_DONE: @@ -731,10 +854,20 @@ static void host_session_msg_hdlr(struct npu_device *npu_dev) msg = kzalloc(sizeof(uint32_t) * NPU_IPC_BUF_LENGTH, GFP_KERNEL); if (!msg) return; + + mutex_lock(&host_ctx->lock); + if (host_ctx->fw_state == FW_DISABLED) { + pr_warn("handle npu session msg when FW is disabled\n"); + goto skip_read_msg; + } + while (npu_host_ipc_read_msg(npu_dev, IPC_QUEUE_APPS_RSP, msg) == 0) { pr_debug("received from msg queue\n"); app_msg_proc(host_ctx, msg); } + +skip_read_msg: + mutex_unlock(&host_ctx->lock); kfree(msg); } @@ -762,15 +895,26 @@ static void log_msg_proc(struct npu_device *npu_dev, uint32_t *msg) static void host_session_log_hdlr(struct npu_device *npu_dev) { uint32_t *msg; + struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; msg = kzalloc(sizeof(uint32_t) * NPU_IPC_BUF_LENGTH, GFP_KERNEL); if (!msg) return; + + mutex_lock(&host_ctx->lock); + if (host_ctx->fw_state == FW_DISABLED) { + pr_warn("handle npu session msg when FW is disabled\n"); + goto skip_read_msg; + } + while (npu_host_ipc_read_msg(npu_dev, IPC_QUEUE_LOG, msg) == 0) { pr_debug("received from log queue\n"); log_msg_proc(npu_dev, msg); } + +skip_read_msg: + mutex_unlock(&host_ctx->lock); kfree(msg); } @@ -818,7 +962,6 @@ static int npu_send_network_cmd(struct npu_device *npu_dev, struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; int ret = 0; - mutex_lock(&host_ctx->lock); if (network->fw_error || host_ctx->fw_error || (host_ctx->fw_state == FW_DISABLED)) { pr_err("fw is in error state or disabled, can't send network cmd\n"); @@ -833,12 +976,12 @@ static int npu_send_network_cmd(struct npu_device *npu_dev, network->cmd_async = async; network->cmd_ret_status = 0; network->cmd_pending = true; + network->trans_id = atomic_read(&host_ctx->ipc_trans_id); ret = npu_host_ipc_send_cmd(npu_dev, IPC_QUEUE_APPS_EXEC, cmd_ptr); if (ret) network->cmd_pending = false; } - mutex_unlock(&host_ctx->lock); return ret; } @@ -938,12 +1081,14 @@ int32_t npu_host_load_network(struct npu_client *client, 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; @@ -984,16 +1129,26 @@ int32_t npu_host_load_network(struct npu_client *client, goto error_free_network; } - if (!wait_for_completion_interruptible_timeout( + 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)) { - pr_err_ratelimited("npu: NPU_IPC_CMD_LOAD time out\n"); + NW_DEBUG_TIMEOUT : NW_CMD_TIMEOUT); + + mutex_lock(&host_ctx->lock); + if (!ret) { + pr_err_ratelimited("NPU_IPC_CMD_LOAD time out\n"); ret = -ETIMEDOUT; goto error_free_network; - } else if (network->fw_error) { + } else if (ret < 0) { + pr_err("NPU_IPC_CMD_LOAD is interrupted by signal\n"); + goto error_free_network; + } + + if (network->fw_error) { ret = -EIO; - pr_err("load cmd returns with error\n"); + pr_err("fw is in error state during load network\n"); goto error_free_network; } @@ -1002,12 +1157,17 @@ int32_t npu_host_load_network(struct npu_client *client, 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: - free_network(host_ctx, network->id); + network_put(network); + free_network(host_ctx, client, network->id); err_deinit_fw: + mutex_unlock(&host_ctx->lock); fw_deinit(npu_dev, false); return ret; } @@ -1028,12 +1188,14 @@ int32_t npu_host_load_network_v2(struct npu_client *client, 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); num_patch_params = load_ioctl->patch_info_num; pkt_size = sizeof(*load_packet) + num_patch_params * sizeof(struct npu_patch_tuple_v2); @@ -1091,16 +1253,27 @@ int32_t npu_host_load_network_v2(struct npu_client *client, goto error_free_network; } - if (!wait_for_completion_interruptible_timeout( + 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)) { + NW_DEBUG_TIMEOUT : NW_CMD_TIMEOUT); + + mutex_lock(&host_ctx->lock); + + if (!ret) { pr_err_ratelimited("npu: NPU_IPC_CMD_LOAD time out\n"); ret = -ETIMEDOUT; goto error_free_network; - } else if (network->fw_error) { + } else if (ret < 0) { + pr_err("NPU_IPC_CMD_LOAD_V2 is interrupted by signal\n"); + goto error_free_network; + } + + if (network->fw_error) { ret = -EIO; - pr_err("load cmd returns with error\n"); + pr_err("fw is in error state during load_v2 network\n"); goto error_free_network; } @@ -1109,13 +1282,18 @@ int32_t npu_host_load_network_v2(struct npu_client *client, 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: kfree(load_packet); - free_network(host_ctx, network->id); + network_put(network); + free_network(host_ctx, client, network->id); err_deinit_fw: + mutex_unlock(&host_ctx->lock); fw_deinit(npu_dev, false); return ret; } @@ -1130,15 +1308,27 @@ int32_t npu_host_unload_network(struct npu_client *client, struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; /* get the corresponding network for ipc trans id purpose */ - network = get_network_by_hdl(host_ctx, unload->network_hdl); - if (!network) + mutex_lock(&host_ctx->lock); + network = get_network_by_hdl(host_ctx, client, + unload->network_hdl); + if (!network) { + mutex_unlock(&host_ctx->lock); return -EINVAL; + } + + if (!network->is_active) { + pr_err("network is not active\n"); + network_put(network); + mutex_unlock(&host_ctx->lock); + return -EINVAL; + } if (network->fw_error) { pr_err("fw in error state, skip unload network in fw\n"); - goto skip_fw; + goto free_network; } + pr_debug("Unload network %d\n", network->id); /* prepare IPC packet for UNLOAD */ unload_packet.header.cmd_type = NPU_IPC_CMD_UNLOAD; unload_packet.header.size = sizeof(struct ipc_cmd_unload_pkt); @@ -1153,23 +1343,55 @@ int32_t npu_host_unload_network(struct npu_client *client, if (ret) { pr_err("NPU_IPC_CMD_UNLOAD sent failed: %d\n", ret); - } else if (!wait_for_completion_interruptible_timeout( + /* + * If another command is running on this network, + * don't free_network now. + */ + if (ret == -EBUSY) { + pr_err("Network is running, retry later\n"); + network_put(network); + mutex_unlock(&host_ctx->lock); + return ret; + } + goto 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)) { + NW_DEBUG_TIMEOUT : NW_CMD_TIMEOUT); + + mutex_lock(&host_ctx->lock); + + if (!ret) { pr_err_ratelimited("npu: NPU_IPC_CMD_UNLOAD time out\n"); + network->cmd_pending = false; ret = -ETIMEDOUT; - } else if (network->fw_error) { + goto free_network; + } else if (ret < 0) { + pr_err("Wait for unload done interrupted by signal\n"); + network->cmd_pending = false; + goto free_network; + } + + if (network->fw_error) { ret = -EIO; - pr_err("unload cmd returns with error\n"); + pr_err("fw is in error state during unload network\n"); + } else { + ret = network->cmd_ret_status; + pr_debug("unload network status %d", ret); } -skip_fw: +free_network: /* * free the network on the kernel if the corresponding ACO * handle is unloaded on the firmware side */ - free_network(host_ctx, network->id); + network_put(network); + free_network(host_ctx, client, network->id); + mutex_unlock(&host_ctx->lock); fw_deinit(npu_dev, false); return ret; } @@ -1186,20 +1408,35 @@ int32_t npu_host_exec_network(struct npu_client *client, struct npu_host_ctx *host_ctx = &npu_dev->host_ctx; bool async_ioctl = !!exec_ioctl->async; - network = get_network_by_hdl(host_ctx, exec_ioctl->network_hdl); + mutex_lock(&host_ctx->lock); + network = get_network_by_hdl(host_ctx, client, + exec_ioctl->network_hdl); - if (!network) + if (!network) { + mutex_unlock(&host_ctx->lock); return -EINVAL; + } + + if (!network->is_active) { + pr_err("network is not active\n"); + ret = -EINVAL; + goto exec_done; + } - if (network->fw_error) - return -EIO; + if (network->fw_error) { + pr_err("fw is in error state\n"); + ret = -EIO; + goto exec_done; + } + pr_debug("execute network %d\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)) { pr_err("Invalid input/output layer num\n"); - return -EINVAL; + ret = -EINVAL; + goto exec_done; } input_off = exec_ioctl->input_layers[0].buf_phys_addr; @@ -1208,7 +1445,8 @@ int32_t npu_host_exec_network(struct npu_client *client, if (!npu_mem_verify_addr(client, input_off) || !npu_mem_verify_addr(client, output_off)) { pr_err("Invalid patch buf address\n"); - return -EINVAL; + ret = -EINVAL; + goto exec_done; } exec_packet.patch_params.num_params = 2; @@ -1233,25 +1471,54 @@ int32_t npu_host_exec_network(struct npu_client *client, if (ret) { pr_err("NPU_IPC_CMD_EXECUTE sent failed: %d\n", ret); - } else if (async_ioctl) { + goto exec_done; + } + + if (async_ioctl) { pr_debug("Async ioctl, return now\n"); - } else if (!wait_for_completion_interruptible_timeout( + goto exec_done; + } + + 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)) { + NW_DEBUG_TIMEOUT : NW_CMD_TIMEOUT); + + mutex_lock(&host_ctx->lock); + if (!ret) { pr_err_ratelimited("npu: NPU_IPC_CMD_EXECUTE time out\n"); /* dump debug stats */ npu_dump_debug_timeout_stats(npu_dev); network->cmd_pending = false; - - /* treat execution timed out as ssr */ - fw_deinit(npu_dev, true); ret = -ETIMEDOUT; - } else if (network->fw_error) { + goto exec_done; + } else if (ret == -ERESTARTSYS) { + pr_err("Wait for execution done interrupted by signal\n"); + network->cmd_pending = false; + goto exec_done; + } + + if (network->fw_error) { ret = -EIO; - pr_err("execute cmd returns with error\n"); + pr_err("fw is in error state during execute network\n"); } else { ret = network->cmd_ret_status; + pr_debug("execution status %d", ret); + } + +exec_done: + network_put(network); + mutex_unlock(&host_ctx->lock); + + /* + * treat network execution timed our or interrupted by signal + * as error in order to force npu fw to stop execution + */ + if ((ret == -ETIMEDOUT) || (ret == -ERESTARTSYS)) { + pr_err("Error handling after execution failure\n"); + host_error_hdlr(npu_dev, true); } return ret; @@ -1270,21 +1537,37 @@ int32_t npu_host_exec_network_v2(struct npu_client *client, bool async_ioctl = !!exec_ioctl->async; int i; - network = get_network_by_hdl(host_ctx, exec_ioctl->network_hdl); + mutex_lock(&host_ctx->lock); + network = get_network_by_hdl(host_ctx, client, + exec_ioctl->network_hdl); - if (!network) + if (!network) { + mutex_unlock(&host_ctx->lock); return -EINVAL; + } - if (network->fw_error) - return -EIO; + if (!network->is_active) { + pr_err("network is not active\n"); + ret = -EINVAL; + goto exec_v2_done; + } + if (network->fw_error) { + pr_err("fw is in error state\n"); + ret = -EIO; + goto exec_v2_done; + } + + pr_debug("execute_v2 network %d\n", network->id); num_patch_params = exec_ioctl->patch_buf_info_num; pkt_size = num_patch_params * sizeof(struct npu_patch_params_v2) + sizeof(*exec_packet); exec_packet = kzalloc(pkt_size, GFP_KERNEL); - if (!exec_packet) - return -ENOMEM; + if (!exec_packet) { + ret = -ENOMEM; + goto exec_v2_done; + } for (i = 0; i < num_patch_params; i++) { exec_packet->patch_params[i].id = patch_buf_info[i].buf_id; @@ -1299,8 +1582,8 @@ int32_t npu_host_exec_network_v2(struct npu_client *client, if (!npu_mem_verify_addr(client, patch_buf_info[i].buf_phys_addr)) { pr_err("Invalid patch value\n"); - kfree(exec_packet); - return -EINVAL; + ret = -EINVAL; + goto free_exec_packet; } } @@ -1325,37 +1608,70 @@ int32_t npu_host_exec_network_v2(struct npu_client *client, if (ret) { pr_err("NPU_IPC_CMD_EXECUTE_V2 sent failed: %d\n", ret); - } else if (async_ioctl) { + goto free_exec_packet; + } + + if (async_ioctl) { pr_debug("Async ioctl, return now\n"); - } else if (!wait_for_completion_interruptible_timeout( + goto free_exec_packet; + } + + 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)) { + NW_DEBUG_TIMEOUT : NW_CMD_TIMEOUT); + + mutex_lock(&host_ctx->lock); + if (!ret) { pr_err_ratelimited("npu: NPU_IPC_CMD_EXECUTE_V2 time out\n"); /* dump debug stats */ npu_dump_debug_timeout_stats(npu_dev); network->cmd_pending = false; - /* treat execution timed out as ssr */ - fw_deinit(npu_dev, true); ret = -ETIMEDOUT; - } else if (network->fw_error) { + goto free_exec_packet; + } else if (ret == -ERESTARTSYS) { + pr_err("Wait for execution_v2 done interrupted by signal\n"); + network->cmd_pending = false; + goto free_exec_packet; + } + + if (network->fw_error) { ret = -EIO; - pr_err("execute cmd returns with error\n"); - } else { - ret = network->cmd_ret_status; - if (!ret) { - exec_ioctl->stats_buf_size = network->stats_buf_size; - if (copy_to_user( - (void __user *)exec_ioctl->stats_buf_addr, - network->stats_buf, - exec_ioctl->stats_buf_size)) { - pr_err("copy stats to user failed\n"); - exec_ioctl->stats_buf_size = 0; - } + pr_err("fw is in error state during execute_v2 network\n"); + goto free_exec_packet; + } + + ret = network->cmd_ret_status; + if (!ret) { + exec_ioctl->stats_buf_size = network->stats_buf_size; + if (copy_to_user( + (void __user *)exec_ioctl->stats_buf_addr, + network->stats_buf, + exec_ioctl->stats_buf_size)) { + pr_err("copy stats to user failed\n"); + exec_ioctl->stats_buf_size = 0; } + } else { + pr_err("execution failed %d\n", ret); } +free_exec_packet: kfree(exec_packet); +exec_v2_done: + network_put(network); + mutex_unlock(&host_ctx->lock); + + /* + * treat network execution timed our or interrupted by signal + * as error in order to force npu fw to stop execution + */ + if ((ret == -ETIMEDOUT) || (ret == -ERESTARTSYS)) { + pr_err("Error handling after execution failure\n"); + host_error_hdlr(npu_dev, true); + } + return ret; } @@ -1381,14 +1697,22 @@ int32_t npu_host_loopback_test(struct npu_device *npu_dev) if (ret) { pr_err("NPU_IPC_CMD_LOOPBACK sent failed: %d\n", ret); - } else if (!wait_for_completion_interruptible_timeout( + goto loopback_exit; + } + + ret = wait_for_completion_interruptible_timeout( &host_ctx->loopback_done, (host_ctx->fw_dbg_mode & FW_DBG_MODE_INC_TIMEOUT) ? - NW_DEBUG_TIMEOUT : NW_CMD_TIMEOUT)) { + NW_DEBUG_TIMEOUT : NW_CMD_TIMEOUT); + + if (!ret) { pr_err_ratelimited("npu: NPU_IPC_CMD_LOOPBACK time out\n"); ret = -ETIMEDOUT; + } else if (ret < 0) { + pr_err("Wait for loopback done interrupted by signal\n"); } +loopback_exit: fw_deinit(npu_dev, false); return ret; diff --git a/drivers/media/platform/msm/npu/npu_mgr.h b/drivers/media/platform/msm/npu/npu_mgr.h index bf498cbe4f75711f7a9420762188bf7990886c71..a4e04b4f57d9b3f212bfd45c18d62c1bf83e46ee 100644 --- a/drivers/media/platform/msm/npu/npu_mgr.h +++ b/drivers/media/platform/msm/npu/npu_mgr.h @@ -54,7 +54,10 @@ struct npu_network { void *stats_buf; void __user *stats_buf_u; uint32_t stats_buf_size; + uint32_t trans_id; + atomic_t ref_cnt; bool is_valid; + bool is_active; bool fw_error; bool cmd_pending; bool cmd_async; diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h index 4ca8ef4fad2aac353986af63a20b62b77b97e943..e2cf9f19ad6d95fab5bcca36a7be5c1ce842f344 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h @@ -46,6 +46,7 @@ #define SDE_MDP_HW_REV_400 SDE_MDP_REV(4, 0, 0) /* sdm845 v1.0 */ #define SDE_MDP_HW_REV_410 SDE_MDP_REV(4, 1, 0) /* sdm670 v1.0 */ #define SDE_MDP_HW_REV_500 SDE_MDP_REV(5, 0, 0) /* sm8150 v1.0 */ +#define SDE_MDP_HW_REV_520 SDE_MDP_REV(5, 2, 0) /* sdmmagpie v1.0 */ #define SDE_MDP_HW_REV_530 SDE_MDP_REV(5, 3, 0) /* sm6150 v1.0 */ #define SDE_MDP_VBIF_4_LEVEL_REMAPPER 4 diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c index e8d87dc150a70bd1cb2bf8e83d23c75376d0caad..9747f63adc7ca1699aa76f0a995c5b771574c6bc 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c @@ -3102,7 +3102,9 @@ static int sde_rotator_hw_rev_init(struct sde_hw_rotator *rot) rot->downscale_caps = "LINEAR/1.5/2/4/8/16/32/64 TILE/1.5/2/4 TP10/1.5/2"; } else if (IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, - SDE_MDP_HW_REV_530)) { + SDE_MDP_HW_REV_530) || + IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, + SDE_MDP_HW_REV_520)) { SDEROT_DBG("Supporting sys cache inline rotation\n"); set_bit(SDE_CAPS_SBUF_1, mdata->sde_caps_map); set_bit(SDE_CAPS_UBWC_2, mdata->sde_caps_map); diff --git a/drivers/media/platform/msm/vidc/governors/msm_vidc_ar50_dyn_gov.c b/drivers/media/platform/msm/vidc/governors/msm_vidc_ar50_dyn_gov.c index 7fd073a140bf002aff1497781a9e3cb5e648f294..b27761a2f10847d1fa8479b0f75dd6e41e60545d 100644 --- a/drivers/media/platform/msm/vidc/governors/msm_vidc_ar50_dyn_gov.c +++ b/drivers/media/platform/msm/vidc/governors/msm_vidc_ar50_dyn_gov.c @@ -407,15 +407,10 @@ static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d, motion_vector_complexity = FP(integer_part, frac_part, 100); - dpb_write_compression_factor = !dpb_compression_enabled ? FP_ONE : - __compression_ratio(__lut(width, height, fps), opb_bpp); - - dpb_write_compression_factor = d->use_dpb_read ? - dpb_read_compression_factor : - dpb_write_compression_factor; + dpb_write_compression_factor = dpb_read_compression_factor; opb_compression_factor = !opb_compression_enabled ? FP_ONE : - __compression_ratio(__lut(width, height, fps), opb_bpp); + dpb_write_compression_factor; llc_ref_read_l2_cache_enabled = llc_vpss_ds_line_buf_enabled = false; if (d->use_sys_cache) { @@ -427,7 +422,7 @@ static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d, lcu_per_frame = DIV_ROUND_UP(width, lcu_size) * DIV_ROUND_UP(height, lcu_size); - bitrate = __lut(width, height, fps)->bitrate; + bitrate = (d->bitrate + 1000000 - 1) / 1000000; bins_to_bit_factor = d->work_mode == VIDC_WORK_MODE_1 ? FP_INT(0) : FP_INT(4); @@ -481,7 +476,7 @@ static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d, if (llc_ref_read_l2_cache_enabled) { row_cache_penalty = FP(1, 30, 100); ddr.dpb_read = fp_div(ddr.dpb_read, row_cache_penalty); - llc.dpb_read = dpb_total - ddr.dpb_read; + llc.dpb_read = dpb_total - ddr.dpb_write - ddr.dpb_read; } opb_factor = dpb_bpp == 8 ? 8 : 4; @@ -507,7 +502,7 @@ static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d, qsmmu_bw_overhead_factor = FP(1, 3, 100); ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor); - llc.total = llc.dpb_read + llc.opb_read; + llc.total = llc.dpb_read + llc.opb_read + ddr.total; /* Dump all the variables for easier debugging */ if (debug) { @@ -644,7 +639,8 @@ static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d, b_frames_enabled = d->b_frames_enabled; width = max(d->input_width, BASELINE_DIMENSIONS.width); height = max(d->input_height, BASELINE_DIMENSIONS.height); - bitrate = __lut(width, height, fps)->bitrate; + bitrate = d->bitrate > 0 ? d->bitrate / 1000000 : + __lut(width, height, fps)->bitrate; lcu_per_frame = DIV_ROUND_UP(width, lcu_size) * DIV_ROUND_UP(height, lcu_size); @@ -688,10 +684,11 @@ static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d, input_compression_factor = FP(integer_part, frac_part, 100); + /* use input cr if it is valid (not 1), otherwise use lut */ original_compression_factor = - original_compression_enabled ? d->use_dpb_read ? - dpb_compression_factor : input_compression_factor : - FP_ONE; + !original_compression_enabled ? FP_ONE : + input_compression_factor != FP_ONE ? input_compression_factor : + __compression_ratio(__lut(width, height, fps), dpb_bpp); ddr.vsp_read = fp_mult(fp_div(FP_INT(bitrate), FP_INT(8)), bins_to_bit_factor); @@ -745,7 +742,7 @@ static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d, llc_ref_y_read -= ref_y_read; - ref_cb_cr_read = fp_mult(ref_cb_cr_bw_factor, dpb_bw_for_1x); + ref_cb_cr_read = fp_mult(ref_cb_cr_bw_factor, dpb_bw_for_1x) / 2; ref_cb_cr_read = fp_div(ref_cb_cr_read, dpb_compression_factor); @@ -767,7 +764,7 @@ static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d, ddr.dpb_write = fp_mult(ddr.dpb_write, FP(1, 50, 100)); - ddr.dpb_write = fp_div(ddr.dpb_write, input_compression_factor); + ddr.dpb_write = fp_div(ddr.dpb_write, dpb_compression_factor); ref_overlap_bw_factor = width <= vertical_tile_width ? FP_INT(0) : FP_INT(1); @@ -789,7 +786,7 @@ static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d, ddr.original_read + ddr.original_write + ddr.dpb_read + ddr.dpb_write; - llc.total = llc.dpb_read + llc.line_buffer; + llc.total = llc.dpb_read + llc.line_buffer + ddr.total; qsmmu_bw_overhead_factor = FP(1, 3, 100); ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor); diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index b480f05e3d093454f544d170c517268f6e3b9f6b..350b37f2a29becdef381a1b5453f0fceaad0ccda 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -437,6 +437,13 @@ static u32 get_frame_size(struct msm_vidc_inst *inst, frame_size = fmt->get_frame_size(plane, inst->capability.mbs_per_frame.max, MB_SIZE_IN_PIXEL); + if (inst->flags & VIDC_SECURE) { + dprintk(VIDC_DBG, + "Change secure input buffer size from %u to %u\n", + frame_size, frame_size / 2); + frame_size = frame_size / 2; + } + if (inst->buffer_size_limit && (inst->buffer_size_limit < frame_size)) { frame_size = inst->buffer_size_limit; diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index dfc21546c0b65c1dff6aba75a3e467e3985f1e9d..14341873ec87a7972ad4b54e9872906f3b3857a8 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -1413,6 +1413,7 @@ int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) break; case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: { + struct hal_buffer_requirements *buff_req_buffer = NULL; struct v4l2_ctrl *hybrid_hp = TRY_GET_CTRL( V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE); if ((ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR_VFR) @@ -1431,6 +1432,40 @@ int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) property_id = HAL_PARAM_VENC_RATE_CONTROL; property_val = ctrl->val; pdata = &property_val; + + if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ || + ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_RC_OFF) { + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, property_id, pdata); + + if (!rc) { + dprintk(VIDC_DBG, + "Control: %x : Name = %s, ID = 0x%x Value = %d\n", + hash32_ptr(inst->session), ctrl->name, + ctrl->id, ctrl->val); + } else { + dprintk(VIDC_ERR, + "Failed to set rate control mode\n"); + break; + } + + rc = msm_comm_try_get_bufreqs(inst); + if (rc) { + dprintk(VIDC_ERR, + "Failed to get buffer requirements: %d\n", rc); + break; + } + buff_req_buffer = + get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT); + + inst->bufq[CAPTURE_PORT].plane_sizes[0] + = buff_req_buffer ? buff_req_buffer->buffer_size : 0; + dprintk(VIDC_INFO, + "Get updated output buffer size %d\n", + inst->bufq[CAPTURE_PORT].plane_sizes[0]); + property_id = 0; + } + break; } case V4L2_CID_MPEG_VIDC_VIDEO_FRAME_QUALITY: diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index c384405fe0e44079fadb8695639c662dce7191ce..179c44fb5e9585727c6f8f3324faf6f3cad1daeb 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -1981,12 +1981,33 @@ static void msm_vidc_cleanup_instance(struct msm_vidc_inst *inst) { struct msm_vidc_buffer *temp, *dummy; struct getprop_buf *temp_prop, *dummy_prop; + struct list_head *ptr, *next; + enum vidc_ports ports[] = {OUTPUT_PORT, CAPTURE_PORT}; + int c = 0; if (!inst) { dprintk(VIDC_ERR, "%s: invalid params\n", __func__); return; } + for (c = 0; c < ARRAY_SIZE(ports); ++c) { + enum vidc_ports port = ports[c]; + + mutex_lock(&inst->bufq[port].lock); + list_for_each_safe(ptr, next, + &inst->bufq[port].vb2_bufq.queued_list) { + struct vb2_buffer *vb = container_of(ptr, + struct vb2_buffer, queued_entry); + if (vb->state == VB2_BUF_STATE_ACTIVE) { + vb->planes[0].bytesused = 0; + print_vb2_buffer(VIDC_ERR, "undequeud vb2", + inst, vb); + vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); + } + } + mutex_unlock(&inst->bufq[port].lock); + } + mutex_lock(&inst->registeredbufs.lock); list_for_each_entry_safe(temp, dummy, &inst->registeredbufs.list, list) { diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c index 749ffea6660bfb2afb18b9e79001e668f9f53a6f..16545c892e166929f15ebffb00cd7464d9a748bd 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c @@ -1255,9 +1255,17 @@ static int msm_vidc_decide_work_mode_ar50(struct msm_vidc_inst *inst) pdata.video_work_mode = VIDC_WORK_MODE_1; break; } - } else if (inst->session_type == MSM_VIDC_ENCODER) + } else if (inst->session_type == MSM_VIDC_ENCODER) { + u32 rc_mode = 0; + pdata.video_work_mode = VIDC_WORK_MODE_1; - else { + rc_mode = msm_comm_g_ctrl_for_id(inst, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE); + if (rc_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR || + rc_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_MBR || + rc_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_MBR_VFR) + pdata.video_work_mode = VIDC_WORK_MODE_2; + } else { return -EINVAL; } diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index 62741e9f1c44bc9bb289885d2fae8f1159db1472..f4630fb36f5055c253d44f61937d3e2771928c8a 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -4512,6 +4512,14 @@ int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst) { int rc = 0, i = 0; union hal_get_property hprop; + enum hal_buffer int_buf[] = { + HAL_BUFFER_INTERNAL_SCRATCH, + HAL_BUFFER_INTERNAL_SCRATCH_1, + HAL_BUFFER_INTERNAL_SCRATCH_2, + HAL_BUFFER_INTERNAL_PERSIST, + HAL_BUFFER_INTERNAL_PERSIST_1, + HAL_BUFFER_INTERNAL_RECON, + }; memset(&hprop, 0x0, sizeof(hprop)); @@ -4522,6 +4530,10 @@ int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst) return rc; } + /* reset internal buffers */ + for (i = 0; i < ARRAY_SIZE(int_buf); i++) + msm_comm_reset_bufreqs(inst, int_buf[i]); + dprintk(VIDC_DBG, "Buffer requirements from HW:\n"); dprintk(VIDC_DBG, "%15s %8s %8s %8s %8s\n", "buffer type", "count", "mincount_host", "mincount_fw", "size"); diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c index 03af199ebb7c02368b24b515e1c98fb4968cb878..49ac53c4a5d06b5b042f41b3614aec0908e9e928 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c @@ -16,12 +16,13 @@ #include "msm_vidc_debug.h" #include "vidc_hfi_api.h" -int msm_vidc_debug = VIDC_ERR | VIDC_WARN; +int msm_vidc_debug = VIDC_ERR | VIDC_WARN | VIDC_FW; EXPORT_SYMBOL(msm_vidc_debug); int msm_vidc_debug_out = VIDC_OUT_PRINTK; EXPORT_SYMBOL(msm_vidc_debug_out); +/* 0x18 = HFI_DEBUG_MSG_FATAL | HFI_DEBUG_MSG_ERROR */ int msm_vidc_fw_debug = 0x18; int msm_vidc_fw_debug_mode = 1; int msm_vidc_fw_low_power_mode = 1; diff --git a/drivers/media/platform/msm/vidc/msm_vidc_platform.c b/drivers/media/platform/msm/vidc/msm_vidc_platform.c index 531ad8ceb67823bff3f4cbc0b00997e33e7c5d35..353b208acae5463994001df62b1fb2690854f836 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_platform.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_platform.c @@ -79,6 +79,18 @@ static struct msm_vidc_codec_data sm8150_codec_data[] = { CODEC_ENTRY(V4L2_PIX_FMT_VP9, MSM_VIDC_DECODER, 10, 200, 200), }; +static struct msm_vidc_codec_data sdmmagpie_codec_data[] = { + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_ENCODER, 10, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_ENCODER, 10, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_ENCODER, 10, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_TME, MSM_VIDC_ENCODER, 0, 540, 540), + CODEC_ENTRY(V4L2_PIX_FMT_MPEG2, MSM_VIDC_DECODER, 10, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_DECODER, 10, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_DECODER, 10, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_DECODER, 10, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_VP9, MSM_VIDC_DECODER, 10, 200, 200), +}; + static struct msm_vidc_codec_data sdm845_codec_data[] = { CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_ENCODER, 125, 675, 320), CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_ENCODER, 125, 675, 320), @@ -149,7 +161,7 @@ static struct msm_vidc_common_data sm6150_common_data[] = { }, { .key = "qcom,max-hw-load", - .value = 1216800, + .value = 1944000, }, { .key = "qcom,max-hq-mbs-per-frame", @@ -157,7 +169,7 @@ static struct msm_vidc_common_data sm6150_common_data[] = { }, { .key = "qcom,max-hq-frames-per-sec", - .value = 60, + .value = 30, }, { .key = "qcom,max-b-frame-size", @@ -264,6 +276,154 @@ static struct msm_vidc_common_data sm8150_common_data[] = { }, }; +static struct msm_vidc_common_data sdmmagpie_common_data_v0[] = { + { + .key = "qcom,never-unload-fw", + .value = 1, + }, + { + .key = "qcom,sw-power-collapse", + .value = 1, + }, + { + .key = "qcom,domain-attr-non-fatal-faults", + .value = 1, + }, + { + .key = "qcom,max-secure-instances", + .value = 2, /* + * As per design driver allows 3rd + * instance as well since the secure + * flags were updated later for the + * current instance. Hence total + * secure sessions would be + * max-secure-instances + 1. + */ + }, + { + .key = "qcom,max-hw-load", + .value = 3110400, /* 4096x2160@90 */ + }, + { + .key = "qcom,max-hq-mbs-per-frame", + .value = 8160, + }, + { + .key = "qcom,max-hq-frames-per-sec", + .value = 60, + }, + { + .key = "qcom,max-b-frame-size", + .value = 8160, + }, + { + .key = "qcom,max-b-frames-per-sec", + .value = 60, + }, + { + .key = "qcom,power-collapse-delay", + .value = 1500, + }, + { + .key = "qcom,hw-resp-timeout", + .value = 1000, + }, + { + .key = "qcom,debug-timeout", + .value = 0, + }, + { + .key = "qcom,domain-cvp", + .value = 1, + }, + { + .key = "qcom,decode-batching", + .value = 1, + }, + { + .key = "qcom,dcvs", + .value = 1, + }, + { + .key = "qcom,fw-cycles", + .value = 733003, + }, +}; + +static struct msm_vidc_common_data sdmmagpie_common_data_v1[] = { + { + .key = "qcom,never-unload-fw", + .value = 1, + }, + { + .key = "qcom,sw-power-collapse", + .value = 1, + }, + { + .key = "qcom,domain-attr-non-fatal-faults", + .value = 1, + }, + { + .key = "qcom,max-secure-instances", + .value = 2, /* + * As per design driver allows 3rd + * instance as well since the secure + * flags were updated later for the + * current instance. Hence total + * secure sessions would be + * max-secure-instances + 1. + */ + }, + { + .key = "qcom,max-hw-load", + .value = 1281600, /* 4k@30 Decode + 1080p@30 Encode */ + }, + { + .key = "qcom,max-hq-mbs-per-frame", + .value = 8160, + }, + { + .key = "qcom,max-hq-frames-per-sec", + .value = 60, + }, + { + .key = "qcom,max-b-frame-size", + .value = 8160, + }, + { + .key = "qcom,max-b-frames-per-sec", + .value = 60, + }, + { + .key = "qcom,power-collapse-delay", + .value = 1500, + }, + { + .key = "qcom,hw-resp-timeout", + .value = 1000, + }, + { + .key = "qcom,debug-timeout", + .value = 0, + }, + { + .key = "qcom,domain-cvp", + .value = 1, + }, + { + .key = "qcom,decode-batching", + .value = 1, + }, + { + .key = "qcom,dcvs", + .value = 1, + }, + { + .key = "qcom,fw-cycles", + .value = 733003, + }, +}; + static struct msm_vidc_common_data sdm845_common_data[] = { { .key = "qcom,never-unload-fw", @@ -477,6 +637,22 @@ static struct msm_vidc_platform_data sm8150_data = { .vpu_ver = VPU_VERSION_5, }; +static struct msm_vidc_platform_data sdmmagpie_data = { + .codec_data = sdmmagpie_codec_data, + .codec_data_length = ARRAY_SIZE(sdmmagpie_codec_data), + .common_data = sdmmagpie_common_data_v0, + .common_data_length = ARRAY_SIZE(sdmmagpie_common_data_v0), + .csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff, + .csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff, + .csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff, + .efuse_data = NULL, + .efuse_data_length = 0, + .sku_version = 0, + .gcc_register_base = GCC_VIDEO_AXI_REG_START_ADDR, + .gcc_register_size = GCC_VIDEO_AXI_REG_SIZE, + .vpu_ver = VPU_VERSION_5, +}; + static struct msm_vidc_platform_data sdm845_data = { .codec_data = sdm845_codec_data, .codec_data_length = ARRAY_SIZE(sdm845_codec_data), @@ -518,6 +694,10 @@ static const struct of_device_id msm_vidc_dt_match[] = { .compatible = "qcom,sm8150-vidc", .data = &sm8150_data, }, + { + .compatible = "qcom,sdmmagpie-vidc", + .data = &sdmmagpie_data, + }, { .compatible = "qcom,sdm845-vidc", .data = &sdm845_data, @@ -603,6 +783,16 @@ void *vidc_get_drv_data(struct device *dev) driver_data->common_data_length = ARRAY_SIZE(sdm670_common_data_v1); } + } else if (!strcmp(match->compatible, "qcom,sdmmagpie-vidc")) { + rc = msm_vidc_read_efuse(driver_data, dev); + if (rc) + goto exit; + + if (driver_data->sku_version == SKU_VERSION_1) { + driver_data->common_data = sdmmagpie_common_data_v1; + driver_data->common_data_length = + ARRAY_SIZE(sdmmagpie_common_data_v1); + } } exit: diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c index c818474464eb2a2ce83a80058d4b3bdff2935b7b..58669671728b40a4873b96b1f858ccca2a29e8fd 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c @@ -122,6 +122,13 @@ static inline void msm_vidc_free_clock_table( res->clock_set.count = 0; } +static inline void msm_vidc_free_cx_ipeak_context( + struct msm_vidc_platform_resources *res) +{ + cx_ipeak_unregister(res->cx_ipeak_context); + res->cx_ipeak_context = NULL; +} + void msm_vidc_free_platform_resources( struct msm_vidc_platform_resources *res) { @@ -132,6 +139,7 @@ void msm_vidc_free_platform_resources( msm_vidc_free_qdss_addr_table(res); msm_vidc_free_bus_vectors(res); msm_vidc_free_buffer_usage_table(res); + msm_vidc_free_cx_ipeak_context(res); } static int msm_vidc_load_reg_table(struct msm_vidc_platform_resources *res) @@ -804,6 +812,48 @@ int read_platform_resources_from_drv_data( } +static int msm_vidc_populate_cx_ipeak_context( + struct msm_vidc_platform_resources *res) +{ + struct platform_device *pdev = res->pdev; + int rc = 0; + + if (of_find_property(pdev->dev.of_node, + "qcom,cx-ipeak-data", NULL)) { + res->cx_ipeak_context = cx_ipeak_register( + pdev->dev.of_node, "qcom,cx-ipeak-data"); + } + + if (IS_ERR(res->cx_ipeak_context)) { + rc = PTR_ERR(res->cx_ipeak_context); + if (rc == -EPROBE_DEFER) + dprintk(VIDC_INFO, + "cx-ipeak register failed. Deferring probe!"); + else + dprintk(VIDC_ERR, + "cx-ipeak register failed. rc: %d", rc); + + res->cx_ipeak_context = NULL; + goto err_cx_ipeak; + } + + if (res->cx_ipeak_context) + dprintk(VIDC_INFO, "cx-ipeak register successful"); + else + dprintk(VIDC_INFO, "cx-ipeak register not implemented"); + + of_property_read_u32(pdev->dev.of_node, + "qcom,clock-freq-threshold", + &res->clk_freq_threshold); + dprintk(VIDC_DBG, "cx ipeak threshold frequency = %u\n", + res->clk_freq_threshold); + + return rc; + +err_cx_ipeak: + return rc; +} + int read_platform_resources_from_dt( struct msm_vidc_platform_resources *res) { @@ -892,8 +942,16 @@ int read_platform_resources_from_dt( "Using fw-bias : %pa", &res->firmware_base); } + rc = msm_vidc_populate_cx_ipeak_context(res); + if (rc) { + dprintk(VIDC_ERR, + "Failed to setup cx-ipeak %d\n", rc); + goto err_register_cx_ipeak; + } + return rc; +err_register_cx_ipeak: err_setup_legacy_cb: msm_vidc_free_allowed_clocks_table(res); err_load_allowed_clocks_table: diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h index fb2a75543b1dc9bae4403a0e99b3d4c5b0ebfd08..48cd7f2910ce403ed39d265dbcbbd91f644359d1 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h @@ -18,6 +18,7 @@ #include #include "msm_vidc.h" #include +#include "soc/qcom/cx_ipeak.h" #define MAX_BUFFER_TYPES 32 @@ -200,6 +201,8 @@ struct msm_vidc_platform_resources { struct msm_vidc_mem_cdsp mem_cdsp; uint32_t vpu_ver; uint32_t fw_cycles; + uint32_t clk_freq_threshold; + struct cx_ipeak_client *cx_ipeak_context; }; static inline bool is_iommu_present(struct msm_vidc_platform_resources *res) diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index cb4fd19e1aa4ebae704759e2fd017c0b5cff3f27..cc2a406ba380b957b184fc6b283b2440725208d5 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -1383,6 +1384,49 @@ static enum hal_default_properties venus_hfi_get_default_properties(void *dev) return prop; } +static int __set_clk_rate(struct venus_hfi_device *device, + struct clock_info *cl, u64 rate) +{ + int rc = 0; + u64 threshold_freq = device->res->clk_freq_threshold; + struct cx_ipeak_client *ipeak = device->res->cx_ipeak_context; + struct clk *clk = cl->clk; + + if (device->clk_freq < threshold_freq && rate >= threshold_freq) { + rc = cx_ipeak_update(ipeak, true); + if (rc) { + dprintk(VIDC_ERR, + "cx_ipeak_update failed! ipeak %pK\n", ipeak); + return rc; + } + dprintk(VIDC_PROF, "cx_ipeak_update: up, clk freq = %lu\n", + device->clk_freq); + } + + rc = clk_set_rate(clk, rate); + if (rc) { + dprintk(VIDC_ERR, + "%s: Failed to set clock rate %llu %s: %d\n", + __func__, rate, cl->name, rc); + return rc; + } + + device->clk_freq = rate; + + if (device->clk_freq >= threshold_freq && rate < threshold_freq) { + rc = cx_ipeak_update(ipeak, false); + if (rc) { + dprintk(VIDC_ERR, + "cx_ipeak_update failed! ipeak %pK\n", ipeak); + return rc; + } + dprintk(VIDC_PROF, "cx_ipeak_update: down, clk freq = %lu\n", + device->clk_freq); + } + + return rc; +} + static int __set_clocks(struct venus_hfi_device *device, u32 freq) { struct clock_info *cl; @@ -1390,14 +1434,9 @@ static int __set_clocks(struct venus_hfi_device *device, u32 freq) venus_hfi_for_each_clock(device, cl) { if (cl->has_scaling) {/* has_scaling */ - device->clk_freq = freq; - rc = clk_set_rate(cl->clk, freq); - if (rc) { - dprintk(VIDC_ERR, - "Failed to set clock rate %u %s: %d %s\n", - freq, cl->name, rc, __func__); + rc = __set_clk_rate(device, cl, freq); + if (rc) return rc; - } trace_msm_vidc_perf_clock_scale(cl->name, freq); dprintk(VIDC_PROF, "Scaling clock %s to %u\n", @@ -3956,7 +3995,8 @@ static inline int __prepare_enable_clks(struct venus_hfi_device *device) * it to the lowest frequency possible */ if (cl->has_scaling) - clk_set_rate(cl->clk, clk_round_rate(cl->clk, 0)); + __set_clk_rate(device, cl, + clk_round_rate(cl->clk, 0)); rc = clk_set_flags(cl->clk, CLKFLAG_RETAIN_PERIPH); if (rc) { diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 9f023bc6e1b7e4dafd861a4a0344bb4868dec6b1..6e6e978263b0218f8f6b8b63f45d380cd9b81ad5 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -305,7 +305,7 @@ static struct clk *isp_xclk_src_get(struct of_phandle_args *clkspec, void *data) static int isp_xclk_init(struct isp_device *isp) { struct device_node *np = isp->dev->of_node; - struct clk_init_data init; + struct clk_init_data init = { 0 }; unsigned int i; for (i = 0; i < ARRAY_SIZE(isp->xclks); ++i) diff --git a/drivers/media/platform/qcom/camss-8x16/camss-csid.c b/drivers/media/platform/qcom/camss-8x16/camss-csid.c index 64df82817de3c4ce7a9314302273320fe5d1bb7b..4882ee25bd754d5a839fd0f8d41beffa2841412a 100644 --- a/drivers/media/platform/qcom/camss-8x16/camss-csid.c +++ b/drivers/media/platform/qcom/camss-8x16/camss-csid.c @@ -392,9 +392,6 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable) !media_entity_remote_pad(&csid->pads[MSM_CSID_PAD_SINK])) return -ENOLINK; - dt = csid_get_fmt_entry(csid->fmt[MSM_CSID_PAD_SRC].code)-> - data_type; - if (tg->enabled) { /* Config Test Generator */ struct v4l2_mbus_framefmt *f = @@ -416,6 +413,9 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable) writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_0(0)); + dt = csid_get_fmt_entry( + csid->fmt[MSM_CSID_PAD_SRC].code)->data_type; + /* 5:0 data type */ val = dt; writel_relaxed(val, csid->base + @@ -425,6 +425,9 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable) val = tg->payload_mode; writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_2(0)); + + df = csid_get_fmt_entry( + csid->fmt[MSM_CSID_PAD_SRC].code)->decode_format; } else { struct csid_phy_config *phy = &csid->phy; @@ -439,13 +442,16 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable) writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_1); + + dt = csid_get_fmt_entry( + csid->fmt[MSM_CSID_PAD_SINK].code)->data_type; + df = csid_get_fmt_entry( + csid->fmt[MSM_CSID_PAD_SINK].code)->decode_format; } /* Config LUT */ dt_shift = (cid % 4) * 8; - df = csid_get_fmt_entry(csid->fmt[MSM_CSID_PAD_SINK].code)-> - decode_format; val = readl_relaxed(csid->base + CAMSS_CSID_CID_LUT_VC_n(vc)); val &= ~(0xff << dt_shift); diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c index 0f0324a14d515552939cc697b03ab0f0575ec30a..85d26713cedb911b3fb6d14505f7f2234832137e 100644 --- a/drivers/media/platform/s3c-camif/camif-capture.c +++ b/drivers/media/platform/s3c-camif/camif-capture.c @@ -117,6 +117,8 @@ static int sensor_set_power(struct camif_dev *camif, int on) if (camif->sensor.power_count == !on) err = v4l2_subdev_call(sensor->sd, core, s_power, on); + if (err == -ENOIOCTLCMD) + err = 0; if (!err) sensor->power_count += on ? 1 : -1; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 8e9531f7f83f54fbb7b1df28f017f61058dcc680..9942932ecbf9c04a716fd1c7706d8496a707d7c8 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -254,24 +254,24 @@ static void s5p_mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx) static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf *dst_buf, *src_buf; - size_t dec_y_addr; + struct s5p_mfc_buf *dst_buf, *src_buf; + u32 dec_y_addr; unsigned int frame_type; /* Make sure we actually have a new frame before continuing. */ frame_type = s5p_mfc_hw_call(dev->mfc_ops, get_dec_frame_type, dev); if (frame_type == S5P_FIMV_DECODE_FRAME_SKIPPED) return; - dec_y_addr = s5p_mfc_hw_call(dev->mfc_ops, get_dec_y_adr, dev); + dec_y_addr = (u32)s5p_mfc_hw_call(dev->mfc_ops, get_dec_y_adr, dev); /* Copy timestamp / timecode from decoded src to dst and set appropriate flags. */ src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); list_for_each_entry(dst_buf, &ctx->dst_queue, list) { - if (vb2_dma_contig_plane_dma_addr(&dst_buf->b->vb2_buf, 0) - == dec_y_addr) { - dst_buf->b->timecode = - src_buf->b->timecode; + u32 addr = (u32)vb2_dma_contig_plane_dma_addr(&dst_buf->b->vb2_buf, 0); + + if (addr == dec_y_addr) { + dst_buf->b->timecode = src_buf->b->timecode; dst_buf->b->vb2_buf.timestamp = src_buf->b->vb2_buf.timestamp; dst_buf->b->flags &= @@ -307,10 +307,10 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err) { struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_buf *dst_buf; - size_t dspl_y_addr; + u32 dspl_y_addr; unsigned int frame_type; - dspl_y_addr = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_y_adr, dev); + dspl_y_addr = (u32)s5p_mfc_hw_call(dev->mfc_ops, get_dspl_y_adr, dev); if (IS_MFCV6_PLUS(dev)) frame_type = s5p_mfc_hw_call(dev->mfc_ops, get_disp_frame_type, ctx); @@ -329,9 +329,10 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err) /* The MFC returns address of the buffer, now we have to * check which videobuf does it correspond to */ list_for_each_entry(dst_buf, &ctx->dst_queue, list) { + u32 addr = (u32)vb2_dma_contig_plane_dma_addr(&dst_buf->b->vb2_buf, 0); + /* Check if this is the buffer we're looking for */ - if (vb2_dma_contig_plane_dma_addr(&dst_buf->b->vb2_buf, 0) - == dspl_y_addr) { + if (addr == dspl_y_addr) { list_del(&dst_buf->list); ctx->dst_queue_cnt--; dst_buf->b->sequence = ctx->sequence; diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c index b421329b21fae5a6b41af48b0e59377d70bc88d5..3d09e1c879217aba7a4853034b8f749be004daaf 100644 --- a/drivers/media/usb/dvb-usb/dw2102.c +++ b/drivers/media/usb/dvb-usb/dw2102.c @@ -2103,14 +2103,12 @@ static struct dvb_usb_device_properties s6x0_properties = { } }; -static struct dvb_usb_device_properties *p1100; static const struct dvb_usb_device_description d1100 = { "Prof 1100 USB ", {&dw2102_table[PROF_1100], NULL}, {NULL}, }; -static struct dvb_usb_device_properties *s660; static const struct dvb_usb_device_description d660 = { "TeVii S660 USB", {&dw2102_table[TEVII_S660], NULL}, @@ -2129,14 +2127,12 @@ static const struct dvb_usb_device_description d480_2 = { {NULL}, }; -static struct dvb_usb_device_properties *p7500; static const struct dvb_usb_device_description d7500 = { "Prof 7500 USB DVB-S2", {&dw2102_table[PROF_7500], NULL}, {NULL}, }; -static struct dvb_usb_device_properties *s421; static const struct dvb_usb_device_description d421 = { "TeVii S421 PCI", {&dw2102_table[TEVII_S421], NULL}, @@ -2336,6 +2332,11 @@ static int dw2102_probe(struct usb_interface *intf, const struct usb_device_id *id) { int retval = -ENOMEM; + struct dvb_usb_device_properties *p1100; + struct dvb_usb_device_properties *s660; + struct dvb_usb_device_properties *p7500; + struct dvb_usb_device_properties *s421; + p1100 = kmemdup(&s6x0_properties, sizeof(struct dvb_usb_device_properties), GFP_KERNEL); if (!p1100) @@ -2404,8 +2405,16 @@ static int dw2102_probe(struct usb_interface *intf, 0 == dvb_usb_device_init(intf, &t220_properties, THIS_MODULE, NULL, adapter_nr) || 0 == dvb_usb_device_init(intf, &tt_s2_4600_properties, - THIS_MODULE, NULL, adapter_nr)) + THIS_MODULE, NULL, adapter_nr)) { + + /* clean up copied properties */ + kfree(s421); + kfree(p7500); + kfree(s660); + kfree(p1100); + return 0; + } retval = -ENODEV; kfree(s421); diff --git a/drivers/media/usb/tm6000/tm6000-dvb.c b/drivers/media/usb/tm6000/tm6000-dvb.c index 097ac321b7e1e35f1d89bd18456ab1d501a20773..349f578273b6ea480077d80d42eb893528afe3bc 100644 --- a/drivers/media/usb/tm6000/tm6000-dvb.c +++ b/drivers/media/usb/tm6000/tm6000-dvb.c @@ -267,6 +267,11 @@ static int register_dvb(struct tm6000_core *dev) ret = dvb_register_adapter(&dvb->adapter, "Trident TVMaster 6000 DVB-T", THIS_MODULE, &dev->udev->dev, adapter_nr); + if (ret < 0) { + pr_err("tm6000: couldn't register the adapter!\n"); + goto err; + } + dvb->adapter.priv = dev; if (dvb->frontend) { diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index fb86d6af398d305a123be15e1b4c574888d1354c..a6d8002918831eebb0e60549e0c68c0fa52e84a6 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -163,14 +163,27 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream, } } +static size_t uvc_video_ctrl_size(struct uvc_streaming *stream) +{ + /* + * Return the size of the video probe and commit controls, which depends + * on the protocol version. + */ + if (stream->dev->uvc_version < 0x0110) + return 26; + else if (stream->dev->uvc_version < 0x0150) + return 34; + else + return 48; +} + static int uvc_get_video_ctrl(struct uvc_streaming *stream, struct uvc_streaming_control *ctrl, int probe, __u8 query) { + __u16 size = uvc_video_ctrl_size(stream); __u8 *data; - __u16 size; int ret; - size = stream->dev->uvc_version >= 0x0110 ? 34 : 26; if ((stream->dev->quirks & UVC_QUIRK_PROBE_DEF) && query == UVC_GET_DEF) return -EIO; @@ -225,7 +238,7 @@ static int uvc_get_video_ctrl(struct uvc_streaming *stream, ctrl->dwMaxVideoFrameSize = get_unaligned_le32(&data[18]); ctrl->dwMaxPayloadTransferSize = get_unaligned_le32(&data[22]); - if (size == 34) { + if (size >= 34) { ctrl->dwClockFrequency = get_unaligned_le32(&data[26]); ctrl->bmFramingInfo = data[30]; ctrl->bPreferedVersion = data[31]; @@ -254,11 +267,10 @@ static int uvc_get_video_ctrl(struct uvc_streaming *stream, static int uvc_set_video_ctrl(struct uvc_streaming *stream, struct uvc_streaming_control *ctrl, int probe) { + __u16 size = uvc_video_ctrl_size(stream); __u8 *data; - __u16 size; int ret; - size = stream->dev->uvc_version >= 0x0110 ? 34 : 26; data = kzalloc(size, GFP_KERNEL); if (data == NULL) return -ENOMEM; @@ -275,7 +287,7 @@ static int uvc_set_video_ctrl(struct uvc_streaming *stream, put_unaligned_le32(ctrl->dwMaxVideoFrameSize, &data[18]); put_unaligned_le32(ctrl->dwMaxPayloadTransferSize, &data[22]); - if (size == 34) { + if (size >= 34) { put_unaligned_le32(ctrl->dwClockFrequency, &data[26]); data[30] = ctrl->bmFramingInfo; data[31] = ctrl->bPreferedVersion; diff --git a/drivers/media/v4l2-core/v4l2-event.c b/drivers/media/v4l2-core/v4l2-event.c index 968c2eb08b5aba52e18e66221a09b1f351b73337..568dd4affb337a7eb65cc4399db8f0084b4e25ee 100644 --- a/drivers/media/v4l2-core/v4l2-event.c +++ b/drivers/media/v4l2-core/v4l2-event.c @@ -115,14 +115,6 @@ static void __v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *e if (sev == NULL) return; - /* - * If the event has been added to the fh->subscribed list, but its - * add op has not completed yet elems will be 0, treat this as - * not being subscribed. - */ - if (!sev->elems) - return; - /* Increase event sequence number on fh. */ fh->sequence++; @@ -208,6 +200,7 @@ int v4l2_event_subscribe(struct v4l2_fh *fh, struct v4l2_subscribed_event *sev, *found_ev; unsigned long flags; unsigned i; + int ret = 0; if (sub->type == V4L2_EVENT_ALL) return -EINVAL; @@ -226,31 +219,36 @@ int v4l2_event_subscribe(struct v4l2_fh *fh, sev->flags = sub->flags; sev->fh = fh; sev->ops = ops; + sev->elems = elems; + + mutex_lock(&fh->subscribe_lock); spin_lock_irqsave(&fh->vdev->fh_lock, flags); found_ev = v4l2_event_subscribed(fh, sub->type, sub->id); - if (!found_ev) - list_add(&sev->list, &fh->subscribed); spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); if (found_ev) { + /* Already listening */ kvfree(sev); - return 0; /* Already listening */ + goto out_unlock; } if (sev->ops && sev->ops->add) { - int ret = sev->ops->add(sev, elems); + ret = sev->ops->add(sev, elems); if (ret) { - sev->ops = NULL; - v4l2_event_unsubscribe(fh, sub); - return ret; + kvfree(sev); + goto out_unlock; } } - /* Mark as ready for use */ - sev->elems = elems; + spin_lock_irqsave(&fh->vdev->fh_lock, flags); + list_add(&sev->list, &fh->subscribed); + spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); - return 0; +out_unlock: + mutex_unlock(&fh->subscribe_lock); + + return ret; } EXPORT_SYMBOL_GPL(v4l2_event_subscribe); @@ -289,6 +287,8 @@ int v4l2_event_unsubscribe(struct v4l2_fh *fh, return 0; } + mutex_lock(&fh->subscribe_lock); + spin_lock_irqsave(&fh->vdev->fh_lock, flags); sev = v4l2_event_subscribed(fh, sub->type, sub->id); @@ -306,6 +306,8 @@ int v4l2_event_unsubscribe(struct v4l2_fh *fh, if (sev && sev->ops && sev->ops->del) sev->ops->del(sev); + mutex_unlock(&fh->subscribe_lock); + kvfree(sev); return 0; diff --git a/drivers/media/v4l2-core/v4l2-fh.c b/drivers/media/v4l2-core/v4l2-fh.c index 3895999bf8805c3c208a4f042cb59b786a6ec44c..c91a7bd3ecfc7d14853b56a8de273d35ac0ff870 100644 --- a/drivers/media/v4l2-core/v4l2-fh.c +++ b/drivers/media/v4l2-core/v4l2-fh.c @@ -45,6 +45,7 @@ void v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev) INIT_LIST_HEAD(&fh->available); INIT_LIST_HEAD(&fh->subscribed); fh->sequence = -1; + mutex_init(&fh->subscribe_lock); } EXPORT_SYMBOL_GPL(v4l2_fh_init); @@ -90,6 +91,7 @@ void v4l2_fh_exit(struct v4l2_fh *fh) return; v4l_disable_media_source(fh->vdev); v4l2_event_unsubscribe_all(fh); + mutex_destroy(&fh->subscribe_lock); fh->vdev = NULL; } EXPORT_SYMBOL_GPL(v4l2_fh_exit); diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 2dbf632c10de350d72dc61f1a0b63343deee84ba..43522a09b11d50e10cad6eda3d39cd21edfbc1c5 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -1373,6 +1373,11 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb) struct vb2_buffer *vb; int ret; + if (q->error) { + dprintk(1, "fatal error occurred on queue\n"); + return -EIO; + } + vb = q->bufs[index]; switch (vb->state) { diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c index 84e313107233ee8b1e86f0610be093eaa5e1637d..7b9052ea74134a2694f8485f48cb589e9624b793 100644 --- a/drivers/mfd/88pm860x-i2c.c +++ b/drivers/mfd/88pm860x-i2c.c @@ -146,14 +146,14 @@ int pm860x_page_reg_write(struct i2c_client *i2c, int reg, unsigned char zero; int ret; - i2c_lock_adapter(i2c->adapter); + i2c_lock_bus(i2c->adapter, I2C_LOCK_SEGMENT); read_device(i2c, 0xFA, 0, &zero); read_device(i2c, 0xFB, 0, &zero); read_device(i2c, 0xFF, 0, &zero); ret = write_device(i2c, reg, 1, &data); read_device(i2c, 0xFE, 0, &zero); read_device(i2c, 0xFC, 0, &zero); - i2c_unlock_adapter(i2c->adapter); + i2c_unlock_bus(i2c->adapter, I2C_LOCK_SEGMENT); return ret; } EXPORT_SYMBOL(pm860x_page_reg_write); @@ -164,14 +164,14 @@ int pm860x_page_bulk_read(struct i2c_client *i2c, int reg, unsigned char zero = 0; int ret; - i2c_lock_adapter(i2c->adapter); + i2c_lock_bus(i2c->adapter, I2C_LOCK_SEGMENT); read_device(i2c, 0xfa, 0, &zero); read_device(i2c, 0xfb, 0, &zero); read_device(i2c, 0xff, 0, &zero); ret = read_device(i2c, reg, count, buf); read_device(i2c, 0xFE, 0, &zero); read_device(i2c, 0xFC, 0, &zero); - i2c_unlock_adapter(i2c->adapter); + i2c_unlock_bus(i2c->adapter, I2C_LOCK_SEGMENT); return ret; } EXPORT_SYMBOL(pm860x_page_bulk_read); diff --git a/drivers/mfd/hi655x-pmic.c b/drivers/mfd/hi655x-pmic.c index c37ccbfd52f2a14be65c0008b96697f55029698c..96c07fa1802adcce7d48f971410096b4b2a4f479 100644 --- a/drivers/mfd/hi655x-pmic.c +++ b/drivers/mfd/hi655x-pmic.c @@ -49,7 +49,7 @@ static struct regmap_config hi655x_regmap_config = { .reg_bits = 32, .reg_stride = HI655X_STRIDE, .val_bits = 8, - .max_register = HI655X_BUS_ADDR(0xFFF), + .max_register = HI655X_BUS_ADDR(0x400) - HI655X_STRIDE, }; static struct resource pwrkey_resources[] = { diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index 40534352e57487191978492991dfe1154d608b02..3270b8dbc94982ebb447d9c3ace5d1000c28a670 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -714,6 +714,7 @@ sm501_create_subdev(struct sm501_devdata *sm, char *name, smdev->pdev.name = name; smdev->pdev.id = sm->pdev_id; smdev->pdev.dev.parent = sm->dev; + smdev->pdev.dev.coherent_dma_mask = 0xffffffff; if (res_count) { smdev->pdev.resource = (struct resource *)(smdev+1); diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c index 0f3fab47fe48052682fc686ee62381dd1e9c719b..7dc1cbcd2fb8951150c633290b02392c4f041543 100644 --- a/drivers/mfd/ti_am335x_tscadc.c +++ b/drivers/mfd/ti_am335x_tscadc.c @@ -210,14 +210,13 @@ static int ti_tscadc_probe(struct platform_device *pdev) * The TSC_ADC_SS controller design assumes the OCP clock is * at least 6x faster than the ADC clock. */ - clk = clk_get(&pdev->dev, "adc_tsc_fck"); + clk = devm_clk_get(&pdev->dev, "adc_tsc_fck"); if (IS_ERR(clk)) { dev_err(&pdev->dev, "failed to get TSC fck\n"); err = PTR_ERR(clk); goto err_disable_clk; } clock_rate = clk_get_rate(clk); - clk_put(clk); tscadc->clk_div = clock_rate / ADC_CLK; /* TSCADC_CLKDIV needs to be configured to the value minus 1 */ diff --git a/drivers/misc/cxl/main.c b/drivers/misc/cxl/main.c index c1ba0d42cbc865467334c25a0b62a3f1f8932a21..e0f29b8a872db807fc7e899d25ecfdc87be156d1 100644 --- a/drivers/misc/cxl/main.c +++ b/drivers/misc/cxl/main.c @@ -287,7 +287,7 @@ int cxl_adapter_context_get(struct cxl *adapter) int rc; rc = atomic_inc_unless_negative(&adapter->contexts_num); - return rc >= 0 ? 0 : -EBUSY; + return rc ? 0 : -EBUSY; } void cxl_adapter_context_put(struct cxl *adapter) diff --git a/drivers/misc/fpr_FingerprintCard/fpc1020_platform_tee.c b/drivers/misc/fpr_FingerprintCard/fpc1020_platform_tee.c index 887c8eb2f9ee5401c628348fa3644a11f541bfbb..a6ed374e5b8e96d129b36e8dcf7d36577420b229 100644 --- a/drivers/misc/fpr_FingerprintCard/fpc1020_platform_tee.c +++ b/drivers/misc/fpr_FingerprintCard/fpc1020_platform_tee.c @@ -75,8 +75,8 @@ static const struct vreg_config vreg_conf[] = { struct fpc1020_data { struct device *dev; struct pinctrl *fingerprint_pinctrl; - struct pinctrl_state **pinctrl_state; - struct regulator **vreg; + struct pinctrl_state *pinctrl_state[ARRAY_SIZE(pctl_names)]; + struct regulator *vreg[ARRAY_SIZE(vreg_conf)]; struct wakeup_source ttw_wl; struct mutex lock; /* To set/get exported values in sysfs */ int irq_gpio; diff --git a/drivers/misc/hmc6352.c b/drivers/misc/hmc6352.c index eeb7eef62174c4dfb5c8854efbef2d798f161f1e..38f90e17992717d7cd0f12ad904490abbaa2d1a5 100644 --- a/drivers/misc/hmc6352.c +++ b/drivers/misc/hmc6352.c @@ -27,6 +27,7 @@ #include #include #include +#include static DEFINE_MUTEX(compass_mutex); @@ -50,6 +51,7 @@ static int compass_store(struct device *dev, const char *buf, size_t count, return ret; if (val >= strlen(map)) return -EINVAL; + val = array_index_nospec(val, strlen(map)); mutex_lock(&compass_mutex); ret = compass_command(c, map[val]); mutex_unlock(&compass_mutex); diff --git a/drivers/misc/mei/bus-fixup.c b/drivers/misc/mei/bus-fixup.c index 0208c4b027c52b54dad37bddb13fe1288347b477..fa0236a5e59a39c751f6b3eee150d37e97836684 100644 --- a/drivers/misc/mei/bus-fixup.c +++ b/drivers/misc/mei/bus-fixup.c @@ -267,7 +267,7 @@ static int mei_nfc_if_version(struct mei_cl *cl, ret = 0; bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length, 0); - if (bytes_recv < if_version_length) { + if (bytes_recv < 0 || bytes_recv < if_version_length) { dev_err(bus->dev, "Could not read IF version\n"); ret = -EIO; goto err; diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 1ac10cb64d6ed3e7d5ad20c1d5ebb1ec323fa05d..37b13bc5c16fe4b7d7ab87d6d4cc6d39b3b9ca33 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -465,17 +465,15 @@ int mei_cldev_enable(struct mei_cl_device *cldev) cl = cldev->cl; + mutex_lock(&bus->device_lock); if (cl->state == MEI_FILE_UNINITIALIZED) { - mutex_lock(&bus->device_lock); ret = mei_cl_link(cl); - mutex_unlock(&bus->device_lock); if (ret) - return ret; + goto out; /* update pointers */ cl->cldev = cldev; } - mutex_lock(&bus->device_lock); if (mei_cl_is_connected(cl)) { ret = 0; goto out; @@ -841,12 +839,13 @@ static void mei_cl_bus_dev_release(struct device *dev) mei_me_cl_put(cldev->me_cl); mei_dev_bus_put(cldev->bus); + mei_cl_unlink(cldev->cl); kfree(cldev->cl); kfree(cldev); } static const struct device_type mei_cl_device_type = { - .release = mei_cl_bus_dev_release, + .release = mei_cl_bus_dev_release, }; /** diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index fe6595fe94f1f4229bd1851cef7d5060952cb294..995ff1b7e7b5b7baf423716ab63d39af903e3e0b 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -1140,15 +1140,18 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) props_res = (struct hbm_props_response *)mei_msg; - if (props_res->status) { + if (props_res->status == MEI_HBMS_CLIENT_NOT_FOUND) { + dev_dbg(dev->dev, "hbm: properties response: %d CLIENT_NOT_FOUND\n", + props_res->me_addr); + } else if (props_res->status) { dev_err(dev->dev, "hbm: properties response: wrong status = %d %s\n", props_res->status, mei_hbm_status_str(props_res->status)); return -EPROTO; + } else { + mei_hbm_me_cl_add(dev, props_res); } - mei_hbm_me_cl_add(dev, props_res); - /* request property for the next client */ if (mei_hbm_prop_req(dev, props_res->me_addr + 1)) return -EIO; diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 22efc039f3022237d1bc65b625cabb6ddb9fa3b1..8d1d40dbf7448fb51f2c8b70e5a88e8a404583f8 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -291,7 +291,6 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, goto out; } - *offset = 0; cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, file); if (!cb) { rets = -ENOMEM; diff --git a/drivers/misc/mic/scif/scif_api.c b/drivers/misc/mic/scif/scif_api.c index ddc9e4b08b5cd809f4ce6e43fe1ec313dfb75e0d..56efa9d18a9afec2ddaea8bb76fc7ec34c14ce78 100644 --- a/drivers/misc/mic/scif/scif_api.c +++ b/drivers/misc/mic/scif/scif_api.c @@ -370,11 +370,10 @@ int scif_bind(scif_epd_t epd, u16 pn) goto scif_bind_exit; } } else { - pn = scif_get_new_port(); - if (!pn) { - ret = -ENOSPC; + ret = scif_get_new_port(); + if (ret < 0) goto scif_bind_exit; - } + pn = ret; } ep->state = SCIFEP_BOUND; @@ -648,13 +647,12 @@ int __scif_connect(scif_epd_t epd, struct scif_port_id *dst, bool non_block) err = -EISCONN; break; case SCIFEP_UNBOUND: - ep->port.port = scif_get_new_port(); - if (!ep->port.port) { - err = -ENOSPC; - } else { - ep->port.node = scif_info.nodeid; - ep->conn_async_state = ASYNC_CONN_IDLE; - } + err = scif_get_new_port(); + if (err < 0) + break; + ep->port.port = err; + ep->port.node = scif_info.nodeid; + ep->conn_async_state = ASYNC_CONN_IDLE; /* Fall through */ case SCIFEP_BOUND: /* diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index ded778f3edcaa43d95b3f6eb2d535a26a3990b89..3df45b3f119332cf8f3f52fe79ef1d6acdc461a5 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -52,6 +52,7 @@ #include #include #include "compat_qseecom.h" +#include #define QSEECOM_DEV "qseecom" #define QSEOS_VERSION_14 0x14 @@ -191,6 +192,7 @@ struct qseecom_registered_listener_list { phys_addr_t sb_phys; size_t sb_length; wait_queue_head_t rcv_req_wq; + /* rcv_req_flag: -1: not ready; 0: ready and empty; 1: received req */ int rcv_req_flag; int send_resp_flag; bool listener_in_use; @@ -1346,7 +1348,7 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data, if (!new_entry) return -ENOMEM; memcpy(&new_entry->svc, &rcvd_lstnr, sizeof(rcvd_lstnr)); - new_entry->rcv_req_flag = 0; + new_entry->rcv_req_flag = -1; new_entry->svc.listener_id = rcvd_lstnr.listener_id; new_entry->sb_length = rcvd_lstnr.sb_size; @@ -1366,7 +1368,7 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data, list_add_tail(&new_entry->list, &qseecom.registered_listener_list_head); spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags); - pr_warn("Service %d is registered\n", rcvd_lstnr.listener_id); + pr_debug("Service %d is registered\n", rcvd_lstnr.listener_id); return ret; } @@ -1440,7 +1442,7 @@ static int qseecom_unregister_listener(struct qseecom_dev_handle *data) kzfree(ptr_svc); data->released = true; - pr_warn("Service %d is unregistered\n", data->listener.id); + pr_debug("Service %d is unregistered\n", data->listener.id); return ret; } @@ -1770,21 +1772,20 @@ static void __qseecom_clean_listener_sglistinfo( } } -/* wake up listener receive request wq retry delay (ms) and max attemp count */ -#define QSEECOM_WAKE_LISTENER_RCVWQ_DELAY 10 -#define QSEECOM_WAKE_LISTENER_RCVWQ_MAX_ATTEMP 3 +/* wait listener retry delay (ms) and max attemp count */ +#define QSEECOM_WAIT_LISTENER_DELAY 10 +#define QSEECOM_WAIT_LISTENER_MAX_ATTEMP 3 -static int __qseecom_retry_wake_up_listener_rcv_wq( +static int __is_listener_rcv_wq_not_ready( struct qseecom_registered_listener_list *ptr_svc) { int retry = 0; - while (ptr_svc->rcv_req_flag == 1 && - retry++ < QSEECOM_WAKE_LISTENER_RCVWQ_MAX_ATTEMP) { - wake_up_interruptible(&ptr_svc->rcv_req_wq); - msleep(QSEECOM_WAKE_LISTENER_RCVWQ_DELAY); + while (ptr_svc->rcv_req_flag == -1 && + retry++ < QSEECOM_WAIT_LISTENER_MAX_ATTEMP) { + msleep(QSEECOM_WAIT_LISTENER_DELAY); } - return ptr_svc->rcv_req_flag == 1; + return ptr_svc->rcv_req_flag == -1; } static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, @@ -1815,6 +1816,8 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head, list) { if (ptr_svc->svc.listener_id == lstnr) { + if (__is_listener_rcv_wq_not_ready(ptr_svc)) + break; ptr_svc->listener_in_use = true; ptr_svc->rcv_req_flag = 1; wake_up_interruptible(&ptr_svc->rcv_req_wq); @@ -1855,14 +1858,15 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, goto err_resp; } - if (ptr_svc->rcv_req_flag == 1 && - __qseecom_retry_wake_up_listener_rcv_wq(ptr_svc)) { + if (ptr_svc->rcv_req_flag == -1) { pr_err("Service %d is not ready to receive request\n", lstnr); rc = -ENOENT; status = QSEOS_RESULT_FAILURE; goto err_resp; + } + pr_debug("waking up rcv_req_wq and waiting for send_resp_wq\n"); /* initialize the new signal mask with all signals*/ @@ -2144,6 +2148,8 @@ static int __qseecom_reentrancy_process_incomplete_cmd( list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head, list) { if (ptr_svc->svc.listener_id == lstnr) { + if (__is_listener_rcv_wq_not_ready(ptr_svc)) + break; ptr_svc->listener_in_use = true; ptr_svc->rcv_req_flag = 1; wake_up_interruptible(&ptr_svc->rcv_req_wq); @@ -2184,14 +2190,15 @@ static int __qseecom_reentrancy_process_incomplete_cmd( goto err_resp; } - if (ptr_svc->rcv_req_flag == 1 && - __qseecom_retry_wake_up_listener_rcv_wq(ptr_svc)) { + if (ptr_svc->rcv_req_flag == -1) { pr_err("Service %d is not ready to receive request\n", lstnr); rc = -ENOENT; status = QSEOS_RESULT_FAILURE; goto err_resp; + } + pr_debug("waking up rcv_req_wq and waiting for send_resp_wq\n"); /* initialize the new signal mask with all signals*/ @@ -3977,7 +3984,7 @@ static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data, { int ret; - ret = (svc->rcv_req_flag != 0); + ret = (svc->rcv_req_flag == 1); return ret || data->abort || svc->abort; } @@ -3991,12 +3998,13 @@ static int qseecom_receive_req(struct qseecom_dev_handle *data) pr_err("Invalid listener ID\n"); return -ENODATA; } + this_lstnr->rcv_req_flag = 0; while (1) { if (wait_event_freezable(this_lstnr->rcv_req_wq, __qseecom_listener_has_rcvd_req(data, this_lstnr))) { - pr_warn("Interrupted: exiting Listener Service = %d\n", + pr_debug("Interrupted: exiting Listener Service = %d\n", (uint32_t)data->listener.id); /* woken up for different reason */ return -ERESTARTSYS; @@ -7734,6 +7742,19 @@ static inline long qseecom_ioctl(struct file *file, qcom_ice_set_fde_flag(ice_data.flag); break; } + case QSEECOM_IOCTL_FBE_CLEAR_KEY: { + struct qseecom_ice_key_data_t key_data; + + ret = copy_from_user(&key_data, argp, sizeof(key_data)); + if (ret) { + pr_err("copy from user failed\n"); + return -EFAULT; + } + pfk_fbe_clear_key((const unsigned char *) key_data.key, + key_data.key_len, (const unsigned char *) + key_data.salt, key_data.salt_len); + break; + } default: pr_err("Invalid IOCTL: 0x%x\n", cmd); return -EINVAL; diff --git a/drivers/misc/sram.c b/drivers/misc/sram.c index fc0415771c0087264436d1ba434eccae8ef78dff..8daefb81ba294ca4a5dd3455b5c9a82ec1ee5f2a 100644 --- a/drivers/misc/sram.c +++ b/drivers/misc/sram.c @@ -391,29 +391,37 @@ static int sram_probe(struct platform_device *pdev) if (IS_ERR(sram->pool)) return PTR_ERR(sram->pool); - ret = sram_reserve_regions(sram, res); - if (ret) - return ret; - sram->clk = devm_clk_get(sram->dev, NULL); if (IS_ERR(sram->clk)) sram->clk = NULL; else clk_prepare_enable(sram->clk); + ret = sram_reserve_regions(sram, res); + if (ret) + goto err_disable_clk; + platform_set_drvdata(pdev, sram); init_func = of_device_get_match_data(&pdev->dev); if (init_func) { ret = init_func(); if (ret) - return ret; + goto err_free_partitions; } dev_dbg(sram->dev, "SRAM pool: %zu KiB @ 0x%p\n", gen_pool_size(sram->pool) / 1024, sram->virt_base); return 0; + +err_free_partitions: + sram_free_partitions(sram); +err_disable_clk: + if (sram->clk) + clk_disable_unprepare(sram->clk); + + return ret; } static int sram_remove(struct platform_device *pdev) diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index b77aacafc3fcd96bd52af1bb55a60123b22bdcf6..dda3ed72d05bc6e1284e8e860c6ac03657025bdb 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -756,14 +756,14 @@ static int kim_probe(struct platform_device *pdev) err = gpio_request(kim_gdata->nshutdown, "kim"); if (unlikely(err)) { pr_err(" gpio %d request failed ", kim_gdata->nshutdown); - return err; + goto err_sysfs_group; } /* Configure nShutdown GPIO as output=0 */ err = gpio_direction_output(kim_gdata->nshutdown, 0); if (unlikely(err)) { pr_err(" unable to configure gpio %d", kim_gdata->nshutdown); - return err; + goto err_sysfs_group; } /* get reference of pdev for request_firmware */ diff --git a/drivers/misc/tsl2550.c b/drivers/misc/tsl2550.c index adf46072cb37d4a41a3ec95a9fd7d8a52890e677..3fce3b6a36246b28f9c81e339ba83bc67f0a08d2 100644 --- a/drivers/misc/tsl2550.c +++ b/drivers/misc/tsl2550.c @@ -177,7 +177,7 @@ static int tsl2550_calculate_lux(u8 ch0, u8 ch1) } else lux = 0; else - return -EAGAIN; + return 0; /* LUX range check */ return lux > TSL2550_MAX_LUX ? TSL2550_MAX_LUX : lux; diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 56c6f79a5c5af83a862cf76352f172f5e02ee0b8..f74166aa9a0dc09037fec9797838c8f78edf156d 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -45,6 +45,7 @@ #include #include #include +#include #include MODULE_AUTHOR("VMware, Inc."); @@ -341,7 +342,13 @@ static bool vmballoon_send_start(struct vmballoon *b, unsigned long req_caps) success = false; } - if (b->capabilities & VMW_BALLOON_BATCHED_2M_CMDS) + /* + * 2MB pages are only supported with batching. If batching is for some + * reason disabled, do not use 2MB pages, since otherwise the legacy + * mechanism is used with 2MB pages, causing a failure. + */ + if ((b->capabilities & VMW_BALLOON_BATCHED_2M_CMDS) && + (b->capabilities & VMW_BALLOON_BATCHED_CMDS)) b->supported_page_sizes = 2; else b->supported_page_sizes = 1; @@ -450,7 +457,7 @@ static int vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn, pfn32 = (u32)pfn; if (pfn32 != pfn) - return -1; + return -EINVAL; STATS_INC(b->stats.lock[false]); @@ -460,7 +467,7 @@ static int vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn, pr_debug("%s - ppn %lx, hv returns %ld\n", __func__, pfn, status); STATS_INC(b->stats.lock_fail[false]); - return 1; + return -EIO; } static int vmballoon_send_batched_lock(struct vmballoon *b, @@ -597,11 +604,12 @@ static int vmballoon_lock_page(struct vmballoon *b, unsigned int num_pages, locked = vmballoon_send_lock_page(b, page_to_pfn(page), &hv_status, target); - if (locked > 0) { + if (locked) { STATS_INC(b->stats.refused_alloc[false]); - if (hv_status == VMW_BALLOON_ERROR_RESET || - hv_status == VMW_BALLOON_ERROR_PPN_NOTNEEDED) { + if (locked == -EIO && + (hv_status == VMW_BALLOON_ERROR_RESET || + hv_status == VMW_BALLOON_ERROR_PPN_NOTNEEDED)) { vmballoon_free_page(page, false); return -EIO; } @@ -617,7 +625,7 @@ static int vmballoon_lock_page(struct vmballoon *b, unsigned int num_pages, } else { vmballoon_free_page(page, false); } - return -EIO; + return locked; } /* track allocated page */ @@ -1029,29 +1037,30 @@ static void vmballoon_vmci_cleanup(struct vmballoon *b) */ static int vmballoon_vmci_init(struct vmballoon *b) { - int error = 0; + unsigned long error, dummy; - if ((b->capabilities & VMW_BALLOON_SIGNALLED_WAKEUP_CMD) != 0) { - error = vmci_doorbell_create(&b->vmci_doorbell, - VMCI_FLAG_DELAYED_CB, - VMCI_PRIVILEGE_FLAG_RESTRICTED, - vmballoon_doorbell, b); - - if (error == VMCI_SUCCESS) { - VMWARE_BALLOON_CMD(VMCI_DOORBELL_SET, - b->vmci_doorbell.context, - b->vmci_doorbell.resource, error); - STATS_INC(b->stats.doorbell_set); - } - } + if ((b->capabilities & VMW_BALLOON_SIGNALLED_WAKEUP_CMD) == 0) + return 0; - if (error != 0) { - vmballoon_vmci_cleanup(b); + error = vmci_doorbell_create(&b->vmci_doorbell, VMCI_FLAG_DELAYED_CB, + VMCI_PRIVILEGE_FLAG_RESTRICTED, + vmballoon_doorbell, b); - return -EIO; - } + if (error != VMCI_SUCCESS) + goto fail; + + error = VMWARE_BALLOON_CMD(VMCI_DOORBELL_SET, b->vmci_doorbell.context, + b->vmci_doorbell.resource, dummy); + + STATS_INC(b->stats.doorbell_set); + + if (error != VMW_BALLOON_SUCCESS) + goto fail; return 0; +fail: + vmballoon_vmci_cleanup(b); + return -EIO; } /* @@ -1289,7 +1298,14 @@ static int __init vmballoon_init(void) return 0; } -module_init(vmballoon_init); + +/* + * Using late_initcall() instead of module_init() allows the balloon to use the + * VMCI doorbell even when the balloon is built into the kernel. Otherwise the + * VMCI is probed only after the balloon is initialized. If the balloon is used + * as a module, late_initcall() is equivalent to module_init(). + */ +late_initcall(vmballoon_init); static void __exit vmballoon_exit(void) { diff --git a/drivers/misc/vmw_vmci/vmci_queue_pair.c b/drivers/misc/vmw_vmci/vmci_queue_pair.c index 8af5c2672f71cec186af5daf4dc50008fe771c7a..b4570d5c1fe7de4be6b0eeca109ea9797a3b1000 100644 --- a/drivers/misc/vmw_vmci/vmci_queue_pair.c +++ b/drivers/misc/vmw_vmci/vmci_queue_pair.c @@ -755,7 +755,7 @@ static int qp_host_get_user_memory(u64 produce_uva, retval = get_user_pages_fast((uintptr_t) produce_uva, produce_q->kernel_if->num_pages, 1, produce_q->kernel_if->u.h.header_page); - if (retval < produce_q->kernel_if->num_pages) { + if (retval < (int)produce_q->kernel_if->num_pages) { pr_debug("get_user_pages_fast(produce) failed (retval=%d)", retval); qp_release_pages(produce_q->kernel_if->u.h.header_page, @@ -767,7 +767,7 @@ static int qp_host_get_user_memory(u64 produce_uva, retval = get_user_pages_fast((uintptr_t) consume_uva, consume_q->kernel_if->num_pages, 1, consume_q->kernel_if->u.h.header_page); - if (retval < consume_q->kernel_if->num_pages) { + if (retval < (int)consume_q->kernel_if->num_pages) { pr_debug("get_user_pages_fast(consume) failed (retval=%d)", retval); qp_release_pages(consume_q->kernel_if->u.h.header_page, diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index bee1ae6f489617c001e4cb6fbe9bb77ee38450ec..ee336a16abe0885da9c394ba4daf15a9ea9b739b 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -182,7 +182,6 @@ static void mmc_blk_put(struct mmc_blk_data *md) md->usage--; if (md->usage == 0) { int devidx = mmc_get_devidx(md->disk); - blk_cleanup_queue(md->queue.queue); ida_simple_remove(&mmc_blk_ida, devidx); put_disk(md->disk); kfree(md); @@ -1601,8 +1600,6 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req, /* We couldn't get a response from the card. Give up. */ if (err) { - if (card->err_in_sdr104) - return ERR_RETRY; /* Check if the card is removed */ if (mmc_detect_card_removed(card->host)) return ERR_NOMEDIUM; @@ -3184,7 +3181,6 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) struct mmc_async_req *new_areq; struct mmc_async_req *old_areq; bool req_pending = true; - bool reset = false; #ifdef CONFIG_MMC_SIMULATE_MAX_SPEED unsigned long waitfor = jiffies; #endif @@ -3235,26 +3231,6 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) old_req = mmc_queue_req_to_req(mq_rq); type = rq_data_dir(old_req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE; - if (card->err_in_sdr104) { - /* - * Data CRC/timeout errors will manifest as CMD/DATA - * ERR. But we'd like to retry these too. - * Moreover, no harm done if this fails too for multiple - * times, we anyway reduce the bus-speed and retry the - * same request. - * If that fails too, we don't override this status. - */ - if (status == MMC_BLK_ABORT || - status == MMC_BLK_CMD_ERR || - status == MMC_BLK_DATA_ERR || - status == MMC_BLK_RETRY) - /* reset on all of these errors and retry */ - reset = true; - - status = MMC_BLK_RETRY; - card->err_in_sdr104 = false; - } - switch (status) { case MMC_BLK_SUCCESS: case MMC_BLK_PARTIAL: @@ -3300,30 +3276,6 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req) retune_retry_done = brq->retune_retry_done; if (retry++ < MMC_BLK_MAX_RETRIES) break; - else if (reset) { - reset = false; - /* - * If we exhaust all the retries due to - * CRC/timeout errors in SDR140 mode with UHS SD - * cards, re-configure the card in SDR50 - * bus-speed mode. - * All subsequent re-init of this card will be - * in SDR50 mode, unless it is removed and - * re-inserted. When new UHS SD cards are - * inserted, it may start at SDR104 mode if - * supported by the card. - */ - pr_err("%s: blocked SDR104, lower the bus-speed (SDR50 / DDR50)\n", - old_req->rq_disk->disk_name); - mmc_host_clear_sdr104(card->host); - mmc_suspend_clk_scaling(card->host); - mmc_blk_reset(md, card->host, type); - /* SDR104 mode is blocked from now on */ - card->sdr104_blocked = true; - /* retry 5 times again */ - retry = 0; - break; - } /* Fall through */ case MMC_BLK_ABORT: if (!mmc_blk_reset(md, card->host, type) && diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index aecdfeaea9b2cd21986922830881f3ded3df6d5b..bca5e906958587a59e451730c05318281820e613 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -453,32 +453,6 @@ int mmc_clk_update_freq(struct mmc_host *host, } EXPORT_SYMBOL(mmc_clk_update_freq); -int mmc_recovery_fallback_lower_speed(struct mmc_host *host) -{ - int err = 0; - - if (!host->card) - return -EINVAL; - - if (host->sdr104_wa && mmc_card_sd(host->card) && - (host->ios.timing == MMC_TIMING_UHS_SDR104) && - !host->card->sdr104_blocked) { - pr_err("%s: %s: blocked SDR104, lower the bus-speed (SDR50 / DDR50)\n", - mmc_hostname(host), __func__); - mmc_host_clear_sdr104(host); - err = mmc_hw_reset(host); - host->card->sdr104_blocked = true; - } else if (mmc_card_sd(host->card)) { - /* If sdr104_wa is not present, just return status */ - err = host->bus_ops->alive(host); - } - if (err) - pr_err("%s: %s: Fallback to lower speed mode failed with err=%d\n", - mmc_hostname(host), __func__, err); - - return err; -} - static int mmc_devfreq_set_target(struct device *dev, unsigned long *freq, u32 devfreq_flags) { @@ -505,33 +479,26 @@ static int mmc_devfreq_set_target(struct device *dev, pr_debug("%s: target freq = %lu (%s)\n", mmc_hostname(host), *freq, current->comm); - if ((clk_scaling->curr_freq == *freq) || - clk_scaling->skip_clk_scale_freq_update) - goto out; - - /* No need to scale the clocks if they are gated */ - if (!host->ios.clock) - goto out; - spin_lock_bh(&clk_scaling->lock); - if (clk_scaling->clk_scaling_in_progress) { - pr_debug("%s: clocks scaling is already in-progress by mmc thread\n", - mmc_hostname(host)); + if (clk_scaling->target_freq == *freq || + clk_scaling->skip_clk_scale_freq_update) { spin_unlock_bh(&clk_scaling->lock); goto out; } + clk_scaling->need_freq_change = true; clk_scaling->target_freq = *freq; clk_scaling->state = *freq < clk_scaling->curr_freq ? MMC_LOAD_LOW : MMC_LOAD_HIGH; spin_unlock_bh(&clk_scaling->lock); - abort = __mmc_claim_host(host, &clk_scaling->devfreq_abort); - if (abort) + if (!clk_scaling->is_suspended && host->ios.clock) + abort = __mmc_claim_host(host, &clk_scaling->devfreq_abort); + else goto out; - if (mmc_card_sd(host->card) && host->card->sdr104_blocked) - goto rel_host; + if (abort) + goto out; /* * In case we were able to claim host there is no need to @@ -541,18 +508,14 @@ static int mmc_devfreq_set_target(struct device *dev, mmc_host_clk_hold(host); err = mmc_clk_update_freq(host, *freq, clk_scaling->state); - if (err && err != -EAGAIN) { + if (err && err != -EAGAIN) pr_err("%s: clock scale to %lu failed with error %d\n", mmc_hostname(host), *freq, err); - err = mmc_recovery_fallback_lower_speed(host); - } else { + else pr_debug("%s: clock change to %lu finished successfully (%s)\n", mmc_hostname(host), *freq, current->comm); - } - mmc_host_clk_release(host); -rel_host: mmc_release_host(host); out: current->flags &= ~PF_MEMALLOC; @@ -571,17 +534,14 @@ void mmc_deferred_scaling(struct mmc_host *host) { unsigned long target_freq; int err; + struct mmc_devfeq_clk_scaling clk_scaling; if (!host->clk_scaling.enable) return; - if (mmc_card_sd(host->card) && host->card->sdr104_blocked) - return; - spin_lock_bh(&host->clk_scaling.lock); - if (host->clk_scaling.clk_scaling_in_progress || - !(host->clk_scaling.need_freq_change)) { + if (!host->clk_scaling.need_freq_change) { spin_unlock_bh(&host->clk_scaling.lock); return; } @@ -589,7 +549,12 @@ void mmc_deferred_scaling(struct mmc_host *host) atomic_inc(&host->clk_scaling.devfreq_abort); target_freq = host->clk_scaling.target_freq; - host->clk_scaling.clk_scaling_in_progress = true; + /* + * Store the clock scaling state while the lock is acquired so that + * if devfreq context modifies clk_scaling, it will get reflected only + * in the next deferred scaling check. + */ + clk_scaling = host->clk_scaling; host->clk_scaling.need_freq_change = false; spin_unlock_bh(&host->clk_scaling.lock); pr_debug("%s: doing deferred frequency change (%lu) (%s)\n", @@ -597,17 +562,15 @@ void mmc_deferred_scaling(struct mmc_host *host) target_freq, current->comm); err = mmc_clk_update_freq(host, target_freq, - host->clk_scaling.state); - if (err && err != -EAGAIN) { + clk_scaling.state); + if (err && err != -EAGAIN) pr_err("%s: failed on deferred scale clocks (%d)\n", mmc_hostname(host), err); - mmc_recovery_fallback_lower_speed(host); - } else { + else pr_debug("%s: clocks were successfully scaled to %lu (%s)\n", mmc_hostname(host), target_freq, current->comm); - } - host->clk_scaling.clk_scaling_in_progress = false; + atomic_dec(&host->clk_scaling.devfreq_abort); } EXPORT_SYMBOL(mmc_deferred_scaling); @@ -737,7 +700,6 @@ int mmc_init_clk_scaling(struct mmc_host *host) spin_lock_init(&host->clk_scaling.lock); atomic_set(&host->clk_scaling.devfreq_abort, 0); host->clk_scaling.curr_freq = host->ios.clock; - host->clk_scaling.clk_scaling_in_progress = false; host->clk_scaling.need_freq_change = false; host->clk_scaling.is_busy_started = false; @@ -808,7 +770,8 @@ int mmc_suspend_clk_scaling(struct mmc_host *host) return -EINVAL; } - if (!mmc_can_scale_clk(host) || !host->clk_scaling.enable) + if (!mmc_can_scale_clk(host) || !host->clk_scaling.enable || + host->clk_scaling.is_suspended) return 0; if (!host->clk_scaling.devfreq) { @@ -825,7 +788,7 @@ int mmc_suspend_clk_scaling(struct mmc_host *host) mmc_hostname(host), __func__); return err; } - host->clk_scaling.enable = false; + host->clk_scaling.is_suspended = true; host->clk_scaling.total_busy_time_us = 0; @@ -879,15 +842,12 @@ int mmc_resume_clk_scaling(struct mmc_host *host) if (host->ios.clock < host->clk_scaling.freq_table[max_clk_idx]) host->clk_scaling.curr_freq = devfreq_min_clk; - host->clk_scaling.clk_scaling_in_progress = false; - host->clk_scaling.need_freq_change = false; - err = devfreq_resume_device(host->clk_scaling.devfreq); if (err) { pr_err("%s: %s: failed to resume devfreq (%d)\n", mmc_hostname(host), __func__, err); } else { - host->clk_scaling.enable = true; + host->clk_scaling.is_suspended = false; pr_debug("%s: devfreq resumed\n", mmc_hostname(host)); } @@ -1078,6 +1038,7 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) mrq->stop->resp[0], mrq->stop->resp[1], mrq->stop->resp[2], mrq->stop->resp[3]); } + mmc_host_clk_release(host); } /* * Request starter must handle retries - see @@ -1086,7 +1047,6 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) if (mrq->done) mrq->done(mrq); - mmc_host_clk_release(host); } EXPORT_SYMBOL(mmc_request_done); @@ -1623,13 +1583,8 @@ void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq) } } if (!cmd->error || !cmd->retries || - mmc_card_removed(host->card)) { - if (cmd->error && !cmd->retries && - cmd->opcode != MMC_SEND_STATUS && - cmd->opcode != MMC_SEND_TUNING_BLOCK) - mmc_recovery_fallback_lower_speed(host); + mmc_card_removed(host->card)) break; - } mmc_retune_recheck(host); @@ -4085,6 +4040,10 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card) struct mmc_host *host = card->host; unsigned int max_discard, max_trim; + if (!host->max_busy_timeout || + (host->caps2 & MMC_CAP2_MAX_DISCARD_SIZE)) + return UINT_MAX; + /* * Without erase_group_def set, MMC erase timeout depends on clock * frequence which can change. In that case, the best choice is @@ -4261,17 +4220,8 @@ int _mmc_detect_card_removed(struct mmc_host *host) } if (ret) { - if (host->ops->get_cd && host->ops->get_cd(host)) { - ret = mmc_recovery_fallback_lower_speed(host); - } else { - mmc_card_set_removed(host->card); - if (host->card->sdr104_blocked) { - mmc_host_set_sdr104(host); - host->card->sdr104_blocked = false; - } - pr_debug("%s: card remove detected\n", - mmc_hostname(host)); - } + mmc_card_set_removed(host->card); + pr_debug("%s: card remove detected\n", mmc_hostname(host)); } return ret; diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 40a0f4e2612517d1f4f27c0ed4613baa62fb603a..847542dba2e5f53778dcb9342cbaf996517f9be2 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -102,6 +102,7 @@ void mmc_init_context_info(struct mmc_host *host); extern bool mmc_can_scale_clk(struct mmc_host *host); extern int mmc_init_clk_scaling(struct mmc_host *host); +extern int mmc_suspend_clk_scaling(struct mmc_host *host); extern int mmc_resume_clk_scaling(struct mmc_host *host); extern int mmc_exit_clk_scaling(struct mmc_host *host); extern unsigned long mmc_get_max_frequency(struct mmc_host *host); diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 46dccab26d29b3a330b8afa076a8000a776a9668..80793c74bd478fbed0d122e17077adb47c1d660a 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -496,6 +496,11 @@ void mmc_add_host_debugfs(struct mmc_host *host) &host->cmdq_thist_enabled)) goto err_node; + if (!debugfs_create_bool("crash_on_err", + 0600, root, + &host->crash_on_err)) + goto err_node; + #ifdef CONFIG_MMC_RING_BUFFER if (!debugfs_create_file("ring_buffer", 0400, root, host, &mmc_ring_buffer_fops)) diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index ce98f7b252cfe0c89c2ab7b39dc40aacfad3d21b..999b097a688382f4b5f2b1f3460d75c25e6cdddf 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -761,6 +761,7 @@ static ssize_t store_enable(struct device *dev, /* Suspend the clock scaling and mask host capability */ if (host->clk_scaling.enable) mmc_suspend_clk_scaling(host); + host->clk_scaling.enable = false; host->caps2 &= ~MMC_CAP2_CLK_SCALE; host->clk_scaling.state = MMC_LOAD_HIGH; /* Set to max. frequency when disabling */ @@ -769,8 +770,10 @@ static ssize_t store_enable(struct device *dev, } else if (value) { /* Unmask host capability and resume scaling */ host->caps2 |= MMC_CAP2_CLK_SCALE; - if (!host->clk_scaling.enable) + if (!host->clk_scaling.enable) { + host->clk_scaling.enable = true; mmc_resume_clk_scaling(host); + } } mmc_put_card(host->card); diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index 804dc190b53c337108cfcb8fe73a2e896eece76c..a9cc0078992bb2507fc2f68cfbeb678dee3e7ce2 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -359,8 +359,12 @@ static int mmc_init_request(struct request_queue *q, struct request *req, { struct mmc_queue_req *mq_rq = req_to_mmc_queue_req(req); struct mmc_queue *mq = q->queuedata; - struct mmc_card *card = mq->card; - struct mmc_host *host = card->host; + struct mmc_host *host; + + if (!mq) + return -ENODEV; + + host = mq->card->host; mq_rq->sg = mmc_alloc_sg(host->max_segs, gfp); if (!mq_rq->sg) @@ -503,6 +507,8 @@ void mmc_cleanup_queue(struct mmc_queue *mq) blk_start_queue(q); spin_unlock_irqrestore(q->queue_lock, flags); + blk_cleanup_queue(q); + mq->card = NULL; } EXPORT_SYMBOL(mmc_cleanup_queue); diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 5924f59773595ca5e584339f0325da4291798dd3..ebbbf8d9a0f3842ced57c82f335005db1b9c1a56 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1308,8 +1308,6 @@ static int _mmc_sd_resume(struct mmc_host *host) } mmc_card_clr_suspended(host->card); - if (host->card->sdr104_blocked) - goto out; err = mmc_resume_clk_scaling(host); if (err) { pr_err("%s: %s: fail to resume clock scaling (%d)\n", diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c index eade0cd87a0b858f99e0fa49e178ea6cf6eefc02..9aff130a735bec1c89bb33042e97524c9dd35b38 100644 --- a/drivers/mmc/host/cmdq_hci.c +++ b/drivers/mmc/host/cmdq_hci.c @@ -925,6 +925,7 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err) pr_err("%s: err: %d status: 0x%08x task-err-info (0x%08lx)\n", mmc_hostname(mmc), err, status, err_info); + cmdq_dumpregs(cq_host); /* * Need to halt CQE in case of error in interrupt context itself * otherwise CQE may proceed with sending CMD to device even if @@ -936,7 +937,6 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err) if (ret) pr_err("%s: %s: halt failed ret=%d\n", mmc_hostname(mmc), __func__, ret); - /* * Clear the CQIS after halting incase of error. This is done * because if CQIS is cleared before halting, the CQ will @@ -947,8 +947,6 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err) */ cmdq_writel(cq_host, status, CQIS); - cmdq_dumpregs(cq_host); - if (!err_info) { /* * It may so happen sometimes for few errors(like ADMA) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 3b5e6d11069bb58b80f3da5f257d617af9664571..9e03fada16dcbb7baa93ab445d2deeeaf6aff5c2 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -2194,6 +2194,7 @@ static int omap_hsmmc_remove(struct platform_device *pdev) dma_release_channel(host->tx_chan); dma_release_channel(host->rx_chan); + dev_pm_clear_wake_irq(host->dev); pm_runtime_dont_use_autosuspend(host->dev); pm_runtime_put_sync(host->dev); pm_runtime_disable(host->dev); diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index 8bae88a150fd45b3284b594d2d090d4f78fe1fc7..713658be66614264640aa27db20b3fbf25a5e51c 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -44,7 +44,7 @@ /* DM_CM_RST */ #define RST_DTRANRST1 BIT(9) #define RST_DTRANRST0 BIT(8) -#define RST_RESERVED_BITS GENMASK_ULL(32, 0) +#define RST_RESERVED_BITS GENMASK_ULL(31, 0) /* DM_CM_INFO1 and DM_CM_INFO1_MASK */ #define INFO1_CLEAR 0 diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index c2f8edbddf8305eaddf36dacefa90bfb2e74c035..2117b35a8342a44d15e9f56625390fc76706f8ce 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -93,6 +93,7 @@ #define CORE_DDR_DLL_LOCK (1 << 11) #define CORE_CLK_PWRSAVE (1 << 1) +#define CORE_VNDR_SPEC_ADMA_ERR_SIZE_EN (1 << 7) #define CORE_HC_MCLK_SEL_DFLT (2 << 8) #define CORE_HC_MCLK_SEL_HS400 (3 << 8) #define CORE_HC_MCLK_SEL_MASK (3 << 8) @@ -4837,6 +4838,12 @@ static int sdhci_msm_probe(struct platform_device *pdev) writel_relaxed(CORE_VENDOR_SPEC_POR_VAL, host->ioaddr + msm_host_offset->CORE_VENDOR_SPEC); + /* This enable ADMA error interrupt in case of length mismatch */ + writel_relaxed((readl_relaxed(host->ioaddr + + msm_host_offset->CORE_VENDOR_SPEC) | + CORE_VNDR_SPEC_ADMA_ERR_SIZE_EN), + host->ioaddr + msm_host_offset->CORE_VENDOR_SPEC); + /* * Ensure SDHCI FIFO is enabled by disabling alternative FIFO */ diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 4ffa6b173a21ef4a09a62108830869de16095ee2..8332f56e6c0da1bf2be953176b219b8ca73ea142 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "sdhci-pltfm.h" #include "sdhci-esdhc.h" @@ -427,6 +428,11 @@ static void esdhc_of_adma_workaround(struct sdhci_host *host, u32 intmask) static int esdhc_of_enable_dma(struct sdhci_host *host) { u32 value; + struct device *dev = mmc_dev(host->mmc); + + if (of_device_is_compatible(dev->of_node, "fsl,ls1043a-esdhc") || + of_device_is_compatible(dev->of_node, "fsl,ls1046a-esdhc")) + dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40)); value = sdhci_readl(host, ESDHC_DMA_SYSCTL); value |= ESDHC_DMA_SNOOP; diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 0cd6fa80db662a3ed2d8b10014047d50af4f2484..ce3f344d2b66ec70cf15c129c1cc89f592e5edfa 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -334,7 +334,8 @@ static const struct sdhci_pltfm_data sdhci_tegra30_pdata = { SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, - .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | + SDHCI_QUIRK2_BROKEN_HS200, .ops = &tegra_sdhci_ops, }; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 7c0898c7b1c01d8863e7391ba6ee229bc1398280..54f4381a7b714403a565daa64a0c8ed29bc4480f 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -157,6 +157,9 @@ void sdhci_dumpregs(struct sdhci_host *host) host->ops->dump_vendor_regs(host); sdhci_dump_state(host); SDHCI_DUMP("============================================\n"); + /* crash the system upon setting this debugfs. */ + if (host->mmc->crash_on_err) + BUG_ON(1); } EXPORT_SYMBOL_GPL(sdhci_dumpregs); @@ -3375,7 +3378,7 @@ static int sdhci_get_data_err(struct sdhci_host *host, u32 intmask) } else if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC)) { host->mmc->err_stats[MMC_ERR_DAT_CRC]++; return -EILSEQ; - } else if (intmask & MMC_ERR_ADMA) { + } else if (intmask & SDHCI_INT_ADMA_ERROR) { host->mmc->err_stats[MMC_ERR_ADMA]++; return -EIO; } @@ -4601,14 +4604,21 @@ int sdhci_setup_host(struct sdhci_host *host) !(mmc->caps2 & MMC_CAP2_NONHOTPLUG) && !host->mmc->extcon) mmc->caps |= MMC_CAP_NEEDS_POLL; - /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */ if (!IS_ERR(mmc->supply.vqmmc)) { ret = regulator_enable(mmc->supply.vqmmc); + + /* If vqmmc provides no 1.8V signalling, then there's no UHS */ if (!regulator_is_supported_voltage(mmc->supply.vqmmc, 1700000, 1950000)) host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50); + + /* In eMMC case vqmmc might be a fixed 1.8V regulator */ + if (!regulator_is_supported_voltage(mmc->supply.vqmmc, 2700000, + 3600000)) + host->flags &= ~SDHCI_SIGNALING_330; + if (ret) { pr_warn("%s: Failed to enable vqmmc regulator: %d\n", mmc_hostname(mmc), ret); @@ -4841,13 +4851,6 @@ int sdhci_setup_host(struct sdhci_host *host) return ret; } - if (mmc->max_segs == 1) { - /* This may alter mmc->*_blk_* parameters */ - ret = sdhci_allocate_bounce_buffer(host); - if (ret) - return ret; - } - return 0; unreg: diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 5dc8bd042cc54b2d07407f123d0ee62bce738594..504e34f295180fd97bec354a01b47c5a484665f9 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -737,8 +737,8 @@ static struct flash_info dataflash_data[] = { { "AT45DB642x", 0x1f2800, 8192, 1056, 11, SUP_POW2PS}, { "at45db642d", 0x1f2800, 8192, 1024, 10, SUP_POW2PS | IS_POW2PS}, - { "AT45DB641E", 0x1f28000100, 32768, 264, 9, SUP_EXTID | SUP_POW2PS}, - { "at45db641e", 0x1f28000100, 32768, 256, 8, SUP_EXTID | SUP_POW2PS | IS_POW2PS}, + { "AT45DB641E", 0x1f28000100ULL, 32768, 264, 9, SUP_EXTID | SUP_POW2PS}, + { "at45db641e", 0x1f28000100ULL, 32768, 256, 8, SUP_EXTID | SUP_POW2PS | IS_POW2PS}, }; static struct flash_info *jedec_lookup(struct spi_device *spi, diff --git a/drivers/mtd/maps/solutionengine.c b/drivers/mtd/maps/solutionengine.c index bb580bc164459a3dee5b27ef34125af8f31ba2d5..c07f21b20463252e63a0ac0f313f75a7c4c05eaa 100644 --- a/drivers/mtd/maps/solutionengine.c +++ b/drivers/mtd/maps/solutionengine.c @@ -59,9 +59,9 @@ static int __init init_soleng_maps(void) return -ENXIO; } } - printk(KERN_NOTICE "Solution Engine: Flash at 0x%08lx, EPROM at 0x%08lx\n", - soleng_flash_map.phys & 0x1fffffff, - soleng_eprom_map.phys & 0x1fffffff); + printk(KERN_NOTICE "Solution Engine: Flash at 0x%pap, EPROM at 0x%pap\n", + &soleng_flash_map.phys, + &soleng_eprom_map.phys); flash_mtd->owner = THIS_MODULE; eprom_mtd = do_map_probe("map_rom", &soleng_eprom_map); diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index b25f444c5914b09980f54c50f88edd3743fe3097..fa4d12217652b542fdd5683a30b6c9cbbbfd9522 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -160,8 +160,12 @@ static ssize_t mtdchar_read(struct file *file, char __user *buf, size_t count, pr_debug("MTD_read\n"); - if (*ppos + count > mtd->size) - count = mtd->size - *ppos; + if (*ppos + count > mtd->size) { + if (*ppos < mtd->size) + count = mtd->size - *ppos; + else + count = 0; + } if (!count) return 0; @@ -246,7 +250,7 @@ static ssize_t mtdchar_write(struct file *file, const char __user *buf, size_t c pr_debug("MTD_write\n"); - if (*ppos == mtd->size) + if (*ppos >= mtd->size) return -ENOSPC; if (*ppos + count > mtd->size) diff --git a/drivers/mtd/nand/atmel/nand-controller.c b/drivers/mtd/nand/atmel/nand-controller.c index 68c9d98a3347c6ad4592979da0693de7cd27ab8e..148744418e82b768c558cf3c7395d77cd9ddba63 100644 --- a/drivers/mtd/nand/atmel/nand-controller.c +++ b/drivers/mtd/nand/atmel/nand-controller.c @@ -129,6 +129,11 @@ #define DEFAULT_TIMEOUT_MS 1000 #define MIN_DMA_LEN 128 +static bool atmel_nand_avoid_dma __read_mostly; + +MODULE_PARM_DESC(avoiddma, "Avoid using DMA"); +module_param_named(avoiddma, atmel_nand_avoid_dma, bool, 0400); + enum atmel_nand_rb_type { ATMEL_NAND_NO_RB, ATMEL_NAND_NATIVE_RB, @@ -1975,7 +1980,7 @@ static int atmel_nand_controller_init(struct atmel_nand_controller *nc, return ret; } - if (nc->caps->has_dma) { + if (nc->caps->has_dma && !atmel_nand_avoid_dma) { dma_cap_mask_t mask; dma_cap_zero(mask); diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 5423c3bb388e560b4746f9581a622956ff53c14f..e9cd9e701f5ea76fddbfdf7b8d1ba278747aa731 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -54,6 +54,9 @@ struct nand_flash_dev nand_flash_ids[] = { { .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} }, SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640, NAND_ECC_INFO(40, SZ_1K), 4 }, + {"NM1484KSLAXAJ-3B 4G 1.8V 8-bit", + { .id = {0x98, 0xac, 0x90, 0x26, 0x76, 0x00, 0x00, 0x00} }, + SZ_4K, SZ_512, SZ_256K, 0, 5, 256, NAND_ECC_INFO(8, SZ_512) }, LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS), LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS), diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c index 3baddfc997d139358ec63ff50f6d66c474e48ad9..b49ca02b399da0f4f2391185eab48081f5f03bd3 100644 --- a/drivers/mtd/nand/qcom_nandc.c +++ b/drivers/mtd/nand/qcom_nandc.c @@ -2544,6 +2544,9 @@ static int qcom_nand_host_init(struct qcom_nand_controller *nandc, nand_set_flash_node(chip, dn); mtd->name = devm_kasprintf(dev, GFP_KERNEL, "qcom_nand.%d", host->cs); + if (!mtd->name) + return -ENOMEM; + mtd->owner = THIS_MODULE; mtd->dev.parent = dev; diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 23a6986d512b4c75ffd22f5ca51b58a8609e5f75..a8f74d9bba4ff82c6d3430e3656f90dc7d5c4b47 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -1615,8 +1615,10 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) cond_resched(); e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL); - if (!e) + if (!e) { + err = -ENOMEM; goto out_free; + } e->pnum = aeb->pnum; e->ec = aeb->ec; @@ -1635,8 +1637,10 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) cond_resched(); e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL); - if (!e) + if (!e) { + err = -ENOMEM; goto out_free; + } e->pnum = aeb->pnum; e->ec = aeb->ec; diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index 9375cef2242053c1f1ade3323d04d7dd4bea77af..3d27616d9c85540304a8d78c4a2f050c0866b9a2 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -283,8 +283,12 @@ static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) case SIOCFINDIPDDPRT: spin_lock_bh(&ipddp_route_lock); rp = __ipddp_find_route(&rcp); - if (rp) - memcpy(&rcp2, rp, sizeof(rcp2)); + if (rp) { + memset(&rcp2, 0, sizeof(rcp2)); + rcp2.ip = rp->ip; + rcp2.at = rp->at; + rcp2.flags = rp->flags; + } spin_unlock_bh(&ipddp_route_lock); if (rp) { diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index ca3fa82316c2a9940865c4b7b056f76fd268db55..d3ce904e929ec81756fdf27ca53921446bbfbe9f 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -1637,8 +1637,6 @@ static int m_can_plat_probe(struct platform_device *pdev) priv->can.clock.freq = clk_get_rate(cclk); priv->mram_base = mram_addr; - m_can_of_parse_mram(priv, mram_config_vals); - platform_set_drvdata(pdev, dev); SET_NETDEV_DEV(dev, &pdev->dev); @@ -1649,6 +1647,8 @@ static int m_can_plat_probe(struct platform_device *pdev) goto failed_free_dev; } + m_can_of_parse_mram(priv, mram_config_vals); + devm_can_led_init(dev); dev_info(&pdev->dev, "%s device registered (irq=%d, version=%d)\n", @@ -1698,8 +1698,6 @@ static __maybe_unused int m_can_resume(struct device *dev) pinctrl_pm_select_default_state(dev); - m_can_init_ram(priv); - priv->can.state = CAN_STATE_ERROR_ACTIVE; if (netif_running(ndev)) { @@ -1709,6 +1707,7 @@ static __maybe_unused int m_can_resume(struct device *dev) if (ret) return ret; + m_can_init_ram(priv); m_can_start(ndev); netif_device_attach(ndev); netif_start_queue(ndev); diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c index c7427bdd3a4bff957aaef3fdb1d2f8ed0ead41cb..2949a381a94dceb2674f150ad5feaf580a201d25 100644 --- a/drivers/net/can/mscan/mpc5xxx_can.c +++ b/drivers/net/can/mscan/mpc5xxx_can.c @@ -86,6 +86,11 @@ static u32 mpc52xx_can_get_clock(struct platform_device *ofdev, return 0; } cdm = of_iomap(np_cdm, 0); + if (!cdm) { + of_node_put(np_cdm); + dev_err(&ofdev->dev, "can't map clock node!\n"); + return 0; + } if (in_8(&cdm->ipb_clk_sel) & 0x1) freq *= 2; diff --git a/drivers/net/ethernet/3com/Kconfig b/drivers/net/ethernet/3com/Kconfig index 5b7658bcf0209546a4577d708123231c55f97960..5c3ef9fc8207e3de01b86e4c538633ecc8a9f273 100644 --- a/drivers/net/ethernet/3com/Kconfig +++ b/drivers/net/ethernet/3com/Kconfig @@ -32,7 +32,7 @@ config EL3 config 3C515 tristate "3c515 ISA \"Fast EtherLink\"" - depends on ISA && ISA_DMA_API + depends on ISA && ISA_DMA_API && !PPC32 ---help--- If you have a 3Com ISA EtherLink XL "Corkscrew" 3c515 Fast Ethernet network card, say Y here. diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index e3b7a71fcad940bad61802a2c77157b9b965713d..1a4ffc5d3da4ebd2a3662a78885a6086f3cdfb40 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -457,7 +457,7 @@ static void ena_com_handle_admin_completion(struct ena_com_admin_queue *admin_qu cqe = &admin_queue->cq.entries[head_masked]; /* Go over all the completions */ - while ((cqe->acq_common_descriptor.flags & + while ((READ_ONCE(cqe->acq_common_descriptor.flags) & ENA_ADMIN_ACQ_COMMON_DESC_PHASE_MASK) == phase) { /* Do not read the rest of the completion entry before the * phase bit was validated @@ -633,7 +633,7 @@ static u32 ena_com_reg_bar_read32(struct ena_com_dev *ena_dev, u16 offset) writel(mmio_read_reg, ena_dev->reg_bar + ENA_REGS_MMIO_REG_READ_OFF); for (i = 0; i < timeout; i++) { - if (read_resp->req_id == mmio_read->seq_num) + if (READ_ONCE(read_resp->req_id) == mmio_read->seq_num) break; udelay(1); @@ -1790,8 +1790,8 @@ void ena_com_aenq_intr_handler(struct ena_com_dev *dev, void *data) aenq_common = &aenq_e->aenq_common_desc; /* Go over all the events */ - while ((aenq_common->flags & ENA_ADMIN_AENQ_COMMON_DESC_PHASE_MASK) == - phase) { + while ((READ_ONCE(aenq_common->flags) & + ENA_ADMIN_AENQ_COMMON_DESC_PHASE_MASK) == phase) { pr_debug("AENQ! Group[%x] Syndrom[%x] timestamp: [%llus]\n", aenq_common->group, aenq_common->syndrom, (u64)aenq_common->timestamp_low + diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 67df5053dc30a85dc09d4ad2e4cd31056dc29509..60b3ee29d82c89ed097736ea3a38187e8dafd658 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -456,7 +456,7 @@ static inline int ena_alloc_rx_page(struct ena_ring *rx_ring, return -ENOMEM; } - dma = dma_map_page(rx_ring->dev, page, 0, PAGE_SIZE, + dma = dma_map_page(rx_ring->dev, page, 0, ENA_PAGE_SIZE, DMA_FROM_DEVICE); if (unlikely(dma_mapping_error(rx_ring->dev, dma))) { u64_stats_update_begin(&rx_ring->syncp); @@ -473,7 +473,7 @@ static inline int ena_alloc_rx_page(struct ena_ring *rx_ring, rx_info->page_offset = 0; ena_buf = &rx_info->ena_buf; ena_buf->paddr = dma; - ena_buf->len = PAGE_SIZE; + ena_buf->len = ENA_PAGE_SIZE; return 0; } @@ -490,7 +490,7 @@ static void ena_free_rx_page(struct ena_ring *rx_ring, return; } - dma_unmap_page(rx_ring->dev, ena_buf->paddr, PAGE_SIZE, + dma_unmap_page(rx_ring->dev, ena_buf->paddr, ENA_PAGE_SIZE, DMA_FROM_DEVICE); __free_page(page); @@ -910,10 +910,10 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring, do { dma_unmap_page(rx_ring->dev, dma_unmap_addr(&rx_info->ena_buf, paddr), - PAGE_SIZE, DMA_FROM_DEVICE); + ENA_PAGE_SIZE, DMA_FROM_DEVICE); skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, rx_info->page, - rx_info->page_offset, len, PAGE_SIZE); + rx_info->page_offset, len, ENA_PAGE_SIZE); netif_dbg(rx_ring->adapter, rx_status, rx_ring->netdev, "rx skb updated. len %d. data_len %d\n", diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h index 29bb5704260bc09b0356b98ad8860d1a6c43b415..3404376c28ca3805564667488152bbc7da9c6329 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.h +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h @@ -350,4 +350,15 @@ void ena_dump_stats_to_buf(struct ena_adapter *adapter, u8 *buf); int ena_get_sset_count(struct net_device *netdev, int sset); +/* The ENA buffer length fields is 16 bit long. So when PAGE_SIZE == 64kB the + * driver passas 0. + * Since the max packet size the ENA handles is ~9kB limit the buffer length to + * 16kB. + */ +#if PAGE_SIZE > SZ_16K +#define ENA_PAGE_SIZE SZ_16K +#else +#define ENA_PAGE_SIZE PAGE_SIZE +#endif + #endif /* !(ENA_H) */ diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig index d5c15e8bb3de706b12d343ee1a50477b23ab3d3f..a8e8f4e9c1bb6009e78150a4665814381c391158 100644 --- a/drivers/net/ethernet/amd/Kconfig +++ b/drivers/net/ethernet/amd/Kconfig @@ -44,7 +44,7 @@ config AMD8111_ETH config LANCE tristate "AMD LANCE and PCnet (AT1500 and NE2100) support" - depends on ISA && ISA_DMA_API && !ARM + depends on ISA && ISA_DMA_API && !ARM && !PPC32 ---help--- If you have a network (Ethernet) card of this type, say Y here. Some LinkSys cards are of this type. @@ -138,7 +138,7 @@ config PCMCIA_NMCLAN config NI65 tristate "NI6510 support" - depends on ISA && ISA_DMA_API && !ARM + depends on ISA && ISA_DMA_API && !ARM && !PPC32 ---help--- If you have a network (Ethernet) card of this type, say Y here. diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c index 45d92304068eb5ddb4d48a7fa57996d340732429..a5eaf174d914c3d7057a51c577d1d9fc8ac8ec85 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c @@ -289,7 +289,7 @@ static int xgbe_alloc_pages(struct xgbe_prv_data *pdata, struct page *pages = NULL; dma_addr_t pages_dma; gfp_t gfp; - int order, ret; + int order; again: order = alloc_order; @@ -316,10 +316,9 @@ static int xgbe_alloc_pages(struct xgbe_prv_data *pdata, /* Map the pages */ pages_dma = dma_map_page(pdata->dev, pages, 0, PAGE_SIZE << order, DMA_FROM_DEVICE); - ret = dma_mapping_error(pdata->dev, pages_dma); - if (ret) { + if (dma_mapping_error(pdata->dev, pages_dma)) { put_page(pages); - return ret; + return -ENOMEM; } pa->pages = pages; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c index 36fddb199160b064f0d2c38363eb7e192437ed2c..f4b3554b0b67bcff2c27318e1ce1c5c1c3fb6032 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c @@ -752,7 +752,7 @@ static int hw_atl_b0_hw_packet_filter_set(struct aq_hw_s *self, rpfl2promiscuous_mode_en_set(self, IS_FILTER_ENABLED(IFF_PROMISC)); rpfl2multicast_flr_en_set(self, - IS_FILTER_ENABLED(IFF_MULTICAST), 0); + IS_FILTER_ENABLED(IFF_ALLMULTI), 0); rpfl2_accept_all_mc_packets_set(self, IS_FILTER_ENABLED(IFF_ALLMULTI)); diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index 8c9986f3fc0186701bd9ae81f27cbb1519e9f25f..3615c2a06fdadf425e45466b58159d3136c88b2d 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -1685,6 +1685,7 @@ static struct sk_buff *atl1c_alloc_skb(struct atl1c_adapter *adapter) skb = build_skb(page_address(page) + adapter->rx_page_offset, adapter->rx_frag_size); if (likely(skb)) { + skb_reserve(skb, NET_SKB_PAD); adapter->rx_page_offset += adapter->rx_frag_size; if (adapter->rx_page_offset >= PAGE_SIZE) adapter->rx_page = NULL; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index 352beff796ae5b090d8e3fa831078cc7182d3a2c..828e2e56b75e7617c03ba328b6a23d1d20299c84 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -1529,6 +1529,7 @@ struct bnx2x { struct link_vars link_vars; u32 link_cnt; struct bnx2x_link_report_data last_reported_link; + bool force_link_down; struct mdio_if_info mdio; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 6465414dad7478ee9b0cda023512a10517cb9049..8498a357d3895f2fbcbaf374444ae84dbd63e906 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -1260,6 +1260,11 @@ void __bnx2x_link_report(struct bnx2x *bp) { struct bnx2x_link_report_data cur_data; + if (bp->force_link_down) { + bp->link_vars.link_up = 0; + return; + } + /* reread mf_cfg */ if (IS_PF(bp) && !CHIP_IS_E1(bp)) bnx2x_read_mf_cfg(bp); @@ -2817,6 +2822,7 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) bp->pending_max = 0; } + bp->force_link_down = false; if (bp->port.pmf) { rc = bnx2x_initial_phy_init(bp, load_mode); if (rc) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index 1e33abde4a3e8c833386df176896ad9684c9dc10..3fd1085a093fa95a6a1bcac895d72a1e5d5063fb 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -3387,14 +3387,18 @@ static int bnx2x_set_rss_flags(struct bnx2x *bp, struct ethtool_rxnfc *info) DP(BNX2X_MSG_ETHTOOL, "rss re-configured, UDP 4-tupple %s\n", udp_rss_requested ? "enabled" : "disabled"); - return bnx2x_rss(bp, &bp->rss_conf_obj, false, true); + if (bp->state == BNX2X_STATE_OPEN) + return bnx2x_rss(bp, &bp->rss_conf_obj, false, + true); } else if ((info->flow_type == UDP_V6_FLOW) && (bp->rss_conf_obj.udp_rss_v6 != udp_rss_requested)) { bp->rss_conf_obj.udp_rss_v6 = udp_rss_requested; DP(BNX2X_MSG_ETHTOOL, "rss re-configured, UDP 4-tupple %s\n", udp_rss_requested ? "enabled" : "disabled"); - return bnx2x_rss(bp, &bp->rss_conf_obj, false, true); + if (bp->state == BNX2X_STATE_OPEN) + return bnx2x_rss(bp, &bp->rss_conf_obj, false, + true); } return 0; @@ -3508,7 +3512,10 @@ static int bnx2x_set_rxfh(struct net_device *dev, const u32 *indir, bp->rss_conf_obj.ind_table[i] = indir[i] + bp->fp->cl_id; } - return bnx2x_config_rss_eth(bp, false); + if (bp->state == BNX2X_STATE_OPEN) + return bnx2x_config_rss_eth(bp, false); + + return 0; } /** diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index e855a271db48e8e6bc58191708c22c6fef0ff3ba..bd3e3f080ebf835d9df96ea07284b561e0c37180 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -10279,6 +10279,12 @@ static void bnx2x_sp_rtnl_task(struct work_struct *work) bp->sp_rtnl_state = 0; smp_mb(); + /* Immediately indicate link as down */ + bp->link_vars.link_up = 0; + bp->force_link_down = true; + netif_carrier_off(bp->dev); + BNX2X_ERR("Indicating link is down due to Tx-timeout\n"); + bnx2x_nic_unload(bp, UNLOAD_NORMAL, true); bnx2x_nic_load(bp, LOAD_NORMAL); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 94931318587c141c81658c6088c2ce76f9654896..937db801928922358cb8607f2f8ad97fb81b2506 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -6348,7 +6348,7 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init) rc = bnxt_request_irq(bp); if (rc) { netdev_err(bp->dev, "bnxt_request_irq err: %x\n", rc); - goto open_err; + goto open_err_irq; } } @@ -6386,6 +6386,8 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init) open_err: bnxt_disable_napi(bp); + +open_err_irq: bnxt_del_napi(bp); open_err_free_mem: @@ -7866,11 +7868,11 @@ int bnxt_get_max_rings(struct bnxt *bp, int *max_rx, int *max_tx, bool shared) int rx, tx, cp; _bnxt_get_max_rings(bp, &rx, &tx, &cp); + *max_rx = rx; + *max_tx = tx; if (!rx || !tx || !cp) return -ENOMEM; - *max_rx = rx; - *max_tx = tx; return bnxt_trim_rings(bp, max_rx, max_tx, cp, shared); } @@ -7884,8 +7886,11 @@ static int bnxt_get_dflt_rings(struct bnxt *bp, int *max_rx, int *max_tx, /* Not enough rings, try disabling agg rings. */ bp->flags &= ~BNXT_FLAG_AGG_RINGS; rc = bnxt_get_max_rings(bp, max_rx, max_tx, shared); - if (rc) + if (rc) { + /* set BNXT_FLAG_AGG_RINGS back for consistency */ + bp->flags |= BNXT_FLAG_AGG_RINGS; return rc; + } bp->flags |= BNXT_FLAG_NO_AGG_RINGS; bp->dev->hw_features &= ~NETIF_F_LRO; bp->dev->features &= ~NETIF_F_LRO; diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index 4c49d0b9774839e073d35914f4932f110a1ec32b..9d499c5c8f8aaa2989190c6203170f6d456b17c6 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -185,6 +185,9 @@ struct bcmgenet_mib_counters { #define UMAC_MAC1 0x010 #define UMAC_MAX_FRAME_LEN 0x014 +#define UMAC_MODE 0x44 +#define MODE_LINK_STATUS (1 << 5) + #define UMAC_EEE_CTRL 0x064 #define EN_LPI_RX_PAUSE (1 << 0) #define EN_LPI_TX_PFC (1 << 1) diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index 18f5723be2c91b1e533a21ef14e342fb9502961c..6ad0ca7ed3e919d0c75f3dd41508f18889523c49 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -115,8 +115,14 @@ void bcmgenet_mii_setup(struct net_device *dev) static int bcmgenet_fixed_phy_link_update(struct net_device *dev, struct fixed_phy_status *status) { - if (dev && dev->phydev && status) - status->link = dev->phydev->link; + struct bcmgenet_priv *priv; + u32 reg; + + if (dev && dev->phydev && status) { + priv = netdev_priv(dev); + reg = bcmgenet_umac_readl(priv, UMAC_MODE); + status->link = !!(reg & MODE_LINK_STATUS); + } return 0; } diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 6df2cad61647a6d7067df5c30371fbd6eda17923..c1787be6a25828f8a0a2521f91839bd7d448cfbd 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -642,7 +642,7 @@ static int macb_halt_tx(struct macb *bp) if (!(status & MACB_BIT(TGO))) return 0; - usleep_range(10, 250); + udelay(250); } while (time_before(halt_time, timeout)); return -ETIMEDOUT; @@ -1884,14 +1884,17 @@ static void macb_reset_hw(struct macb *bp) { struct macb_queue *queue; unsigned int q; + u32 ctrl = macb_readl(bp, NCR); /* Disable RX and TX (XXX: Should we halt the transmission * more gracefully?) */ - macb_writel(bp, NCR, 0); + ctrl &= ~(MACB_BIT(RE) | MACB_BIT(TE)); /* Clear the stats registers (XXX: Update stats first?) */ - macb_writel(bp, NCR, MACB_BIT(CLRSTAT)); + ctrl |= MACB_BIT(CLRSTAT); + + macb_writel(bp, NCR, ctrl); /* Clear all status flags */ macb_writel(bp, TSR, -1); @@ -2070,7 +2073,7 @@ static void macb_init_hw(struct macb *bp) } /* Enable TX and RX */ - macb_writel(bp, NCR, MACB_BIT(RE) | MACB_BIT(TE) | MACB_BIT(MPE)); + macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(RE) | MACB_BIT(TE)); } /* The hash address register is 64 bits long and takes up two diff --git a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c index e8b290473ee25fe3c6f5b9683c86b87254d3767b..2e089b5ff8f327aeb2dbbac6f0076518d75d3de5 100644 --- a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c +++ b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c @@ -493,6 +493,9 @@ static void cn23xx_pf_setup_global_output_regs(struct octeon_device *oct) for (q_no = srn; q_no < ern; q_no++) { reg_val = octeon_read_csr(oct, CN23XX_SLI_OQ_PKT_CONTROL(q_no)); + /* clear IPTR */ + reg_val &= ~CN23XX_PKT_OUTPUT_CTL_IPTR; + /* set DPTR */ reg_val |= CN23XX_PKT_OUTPUT_CTL_DPTR; diff --git a/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c b/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c index 9338a00083788059736edefd472710c00b30f9af..1f8b7f65125401ef250f9cf57c266fbb55da3f38 100644 --- a/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c +++ b/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c @@ -165,6 +165,9 @@ static void cn23xx_vf_setup_global_output_regs(struct octeon_device *oct) reg_val = octeon_read_csr(oct, CN23XX_VF_SLI_OQ_PKT_CONTROL(q_no)); + /* clear IPTR */ + reg_val &= ~CN23XX_PKT_OUTPUT_CTL_IPTR; + /* set DPTR */ reg_val |= CN23XX_PKT_OUTPUT_CTL_DPTR; diff --git a/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c b/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c index 2887bcaf6af56890fbcf5e9f915151d5c08dc455..45c51277e0cf094b53136f466f99d74eca4542e5 100644 --- a/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c +++ b/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c @@ -643,13 +643,21 @@ static int octeon_mgmt_set_mac_address(struct net_device *netdev, void *addr) static int octeon_mgmt_change_mtu(struct net_device *netdev, int new_mtu) { struct octeon_mgmt *p = netdev_priv(netdev); - int size_without_fcs = new_mtu + OCTEON_MGMT_RX_HEADROOM; + int max_packet = new_mtu + ETH_HLEN + ETH_FCS_LEN; netdev->mtu = new_mtu; - cvmx_write_csr(p->agl + AGL_GMX_RX_FRM_MAX, size_without_fcs); + /* HW lifts the limit if the frame is VLAN tagged + * (+4 bytes per each tag, up to two tags) + */ + cvmx_write_csr(p->agl + AGL_GMX_RX_FRM_MAX, max_packet); + /* Set the hardware to truncate packets larger than the MTU. The jabber + * register must be set to a multiple of 8 bytes, so round up. JABBER is + * an unconditional limit, so we need to account for two possible VLAN + * tags. + */ cvmx_write_csr(p->agl + AGL_GMX_RX_JABBER, - (size_without_fcs + 7) & 0xfff8); + (max_packet + 7 + VLAN_HLEN * 2) & 0xfff8); return 0; } diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 44a0d04dd8a033e05507d40569a0e9b2642ee9a9..74a42f12064b6aced2f5813ef96ed92a10ce0c2a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -253,7 +253,7 @@ static void dcb_tx_queue_prio_enable(struct net_device *dev, int enable) "Can't %s DCB Priority on port %d, TX Queue %d: err=%d\n", enable ? "set" : "unset", pi->port_id, i, -err); else - txq->dcb_prio = value; + txq->dcb_prio = enable ? value : 0; } } diff --git a/drivers/net/ethernet/cirrus/Kconfig b/drivers/net/ethernet/cirrus/Kconfig index 5ab912937aff2e8eb34887deb2aa36c8f45bebde..ec0b545197e2dfd7c0443917c0ec0f33861c77bd 100644 --- a/drivers/net/ethernet/cirrus/Kconfig +++ b/drivers/net/ethernet/cirrus/Kconfig @@ -19,6 +19,7 @@ if NET_VENDOR_CIRRUS config CS89x0 tristate "CS89x0 support" depends on ISA || EISA || ARM + depends on !PPC32 ---help--- Support for CS89x0 chipset based Ethernet cards. If you have a network (Ethernet) card of this type, say Y and read the file diff --git a/drivers/net/ethernet/cisco/enic/enic_clsf.c b/drivers/net/ethernet/cisco/enic/enic_clsf.c index 8dc21c9f97168e1a0a12bcf2c0d6b9ea224fa42f..df613a87ccfffb1e4fe19e6107be316a8e67f82a 100644 --- a/drivers/net/ethernet/cisco/enic/enic_clsf.c +++ b/drivers/net/ethernet/cisco/enic/enic_clsf.c @@ -79,7 +79,6 @@ void enic_rfs_flw_tbl_init(struct enic *enic) enic->rfs_h.max = enic->config.num_arfs; enic->rfs_h.free = enic->rfs_h.max; enic->rfs_h.toclean = 0; - enic_rfs_timer_start(enic); } void enic_rfs_flw_tbl_free(struct enic *enic) @@ -88,7 +87,6 @@ void enic_rfs_flw_tbl_free(struct enic *enic) enic_rfs_timer_stop(enic); spin_lock_bh(&enic->rfs_h.lock); - enic->rfs_h.free = 0; for (i = 0; i < (1 << ENIC_RFS_FLW_BITSHIFT); i++) { struct hlist_head *hhead; struct hlist_node *tmp; @@ -99,6 +97,7 @@ void enic_rfs_flw_tbl_free(struct enic *enic) enic_delfltr(enic, n->fltr_id); hlist_del(&n->node); kfree(n); + enic->rfs_h.free++; } } spin_unlock_bh(&enic->rfs_h.lock); diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index a03a32a4ffca4928bf4132aa31a33c28f9d48c98..2bfaf3e118b1ea7ef28bdab16084dcf470d651ba 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -1930,7 +1930,7 @@ static int enic_open(struct net_device *netdev) vnic_intr_unmask(&enic->intr[i]); enic_notify_timer_start(enic); - enic_rfs_flw_tbl_init(enic); + enic_rfs_timer_start(enic); return 0; @@ -2007,28 +2007,42 @@ static int enic_stop(struct net_device *netdev) return 0; } +static int _enic_change_mtu(struct net_device *netdev, int new_mtu) +{ + bool running = netif_running(netdev); + int err = 0; + + ASSERT_RTNL(); + if (running) { + err = enic_stop(netdev); + if (err) + return err; + } + + netdev->mtu = new_mtu; + + if (running) { + err = enic_open(netdev); + if (err) + return err; + } + + return 0; +} + static int enic_change_mtu(struct net_device *netdev, int new_mtu) { struct enic *enic = netdev_priv(netdev); - int running = netif_running(netdev); if (enic_is_dynamic(enic) || enic_is_sriov_vf(enic)) return -EOPNOTSUPP; - if (running) - enic_stop(netdev); - - netdev->mtu = new_mtu; - if (netdev->mtu > enic->port_mtu) netdev_warn(netdev, - "interface MTU (%d) set higher than port MTU (%d)\n", - netdev->mtu, enic->port_mtu); + "interface MTU (%d) set higher than port MTU (%d)\n", + netdev->mtu, enic->port_mtu); - if (running) - enic_open(netdev); - - return 0; + return _enic_change_mtu(netdev, new_mtu); } static void enic_change_mtu_work(struct work_struct *work) @@ -2036,47 +2050,9 @@ static void enic_change_mtu_work(struct work_struct *work) struct enic *enic = container_of(work, struct enic, change_mtu_work); struct net_device *netdev = enic->netdev; int new_mtu = vnic_dev_mtu(enic->vdev); - int err; - unsigned int i; - - new_mtu = max_t(int, ENIC_MIN_MTU, min_t(int, ENIC_MAX_MTU, new_mtu)); rtnl_lock(); - - /* Stop RQ */ - del_timer_sync(&enic->notify_timer); - - for (i = 0; i < enic->rq_count; i++) - napi_disable(&enic->napi[i]); - - vnic_intr_mask(&enic->intr[0]); - enic_synchronize_irqs(enic); - err = vnic_rq_disable(&enic->rq[0]); - if (err) { - rtnl_unlock(); - netdev_err(netdev, "Unable to disable RQ.\n"); - return; - } - vnic_rq_clean(&enic->rq[0], enic_free_rq_buf); - vnic_cq_clean(&enic->cq[0]); - vnic_intr_clean(&enic->intr[0]); - - /* Fill RQ with new_mtu-sized buffers */ - netdev->mtu = new_mtu; - vnic_rq_fill(&enic->rq[0], enic_rq_alloc_buf); - /* Need at least one buffer on ring to get going */ - if (vnic_rq_desc_used(&enic->rq[0]) == 0) { - rtnl_unlock(); - netdev_err(netdev, "Unable to alloc receive buffers.\n"); - return; - } - - /* Start RQ */ - vnic_rq_enable(&enic->rq[0]); - napi_enable(&enic->napi[0]); - vnic_intr_unmask(&enic->intr[0]); - enic_notify_timer_start(enic); - + (void)_enic_change_mtu(netdev, new_mtu); rtnl_unlock(); netdev_info(netdev, "interface MTU set as %d\n", netdev->mtu); @@ -2854,6 +2830,7 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) enic->notify_timer.function = enic_notify_timer; enic->notify_timer.data = (unsigned long)enic; + enic_rfs_flw_tbl_init(enic); enic_set_rx_coal_setting(enic); INIT_WORK(&enic->reset, enic_reset); INIT_WORK(&enic->tx_hang_reset, enic_tx_hang_reset); @@ -2866,7 +2843,6 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) */ enic->port_mtu = enic->config.mtu; - (void)enic_change_mtu(netdev, enic->port_mtu); err = enic_set_mac_addr(netdev, enic->mac_addr); if (err) { @@ -2953,6 +2929,7 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* MTU range: 68 - 9000 */ netdev->min_mtu = ENIC_MIN_MTU; netdev->max_mtu = ENIC_MAX_MTU; + netdev->mtu = enic->port_mtu; err = register_netdev(netdev); if (err) { diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 02dd5246dfae9a99b20f2bb4b2b13185d3239a3c..1589a568bfe0ab67c2745ea95c28b6749d6895f5 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -4500,7 +4500,7 @@ int be_cmd_get_profile_config(struct be_adapter *adapter, port_res->max_vfs += le16_to_cpu(pcie->num_vfs); } } - return status; + goto err; } pcie = be_get_pcie_desc(resp->func_param, desc_count, diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index 519a021c0a25b41a8102819c21785b1af9d77dab..a202c50d6fc7659d87e6d0763442caed78f96254 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -125,6 +125,9 @@ MODULE_PARM_DESC(tx_timeout, "The Tx timeout in ms"); /* Default alignment for start of data in an Rx FD */ #define DPAA_FD_DATA_ALIGNMENT 16 +/* The DPAA requires 256 bytes reserved and mapped for the SGT */ +#define DPAA_SGT_SIZE 256 + /* Values for the L3R field of the FM Parse Results */ /* L3 Type field: First IP Present IPv4 */ @@ -1622,8 +1625,8 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct dpaa_priv *priv, if (unlikely(qm_fd_get_format(fd) == qm_fd_sg)) { nr_frags = skb_shinfo(skb)->nr_frags; - dma_unmap_single(dev, addr, qm_fd_get_offset(fd) + - sizeof(struct qm_sg_entry) * (1 + nr_frags), + dma_unmap_single(dev, addr, + qm_fd_get_offset(fd) + DPAA_SGT_SIZE, dma_dir); /* The sgt buffer has been allocated with netdev_alloc_frag(), @@ -1907,8 +1910,7 @@ static int skb_to_sg_fd(struct dpaa_priv *priv, void *sgt_buf; /* get a page frag to store the SGTable */ - sz = SKB_DATA_ALIGN(priv->tx_headroom + - sizeof(struct qm_sg_entry) * (1 + nr_frags)); + sz = SKB_DATA_ALIGN(priv->tx_headroom + DPAA_SGT_SIZE); sgt_buf = netdev_alloc_frag(sz); if (unlikely(!sgt_buf)) { netdev_err(net_dev, "netdev_alloc_frag() failed for size %d\n", @@ -1976,9 +1978,8 @@ static int skb_to_sg_fd(struct dpaa_priv *priv, skbh = (struct sk_buff **)buffer_start; *skbh = skb; - addr = dma_map_single(dev, buffer_start, priv->tx_headroom + - sizeof(struct qm_sg_entry) * (1 + nr_frags), - dma_dir); + addr = dma_map_single(dev, buffer_start, + priv->tx_headroom + DPAA_SGT_SIZE, dma_dir); if (unlikely(dma_mapping_error(dev, addr))) { dev_err(dev, "DMA mapping failed"); err = -EINVAL; diff --git a/drivers/net/ethernet/freescale/fman/fman_port.c b/drivers/net/ethernet/freescale/fman/fman_port.c index 1789b206be58396f3d1eca908d3f36289375ac9b..495190764155abdea8df91bacd686d3d902ca81a 100644 --- a/drivers/net/ethernet/freescale/fman/fman_port.c +++ b/drivers/net/ethernet/freescale/fman/fman_port.c @@ -324,6 +324,10 @@ struct fman_port_qmi_regs { #define HWP_HXS_PHE_REPORT 0x00000800 #define HWP_HXS_PCAC_PSTAT 0x00000100 #define HWP_HXS_PCAC_PSTOP 0x00000001 +#define HWP_HXS_TCP_OFFSET 0xA +#define HWP_HXS_UDP_OFFSET 0xB +#define HWP_HXS_SH_PAD_REM 0x80000000 + struct fman_port_hwp_regs { struct { u32 ssa; /* Soft Sequence Attachment */ @@ -728,6 +732,10 @@ static void init_hwp(struct fman_port *port) iowrite32be(0xffffffff, ®s->pmda[i].lcv); } + /* Short packet padding removal from checksum calculation */ + iowrite32be(HWP_HXS_SH_PAD_REM, ®s->pmda[HWP_HXS_TCP_OFFSET].ssa); + iowrite32be(HWP_HXS_SH_PAD_REM, ®s->pmda[HWP_HXS_UDP_OFFSET].ssa); + start_port_hwp(port); } diff --git a/drivers/net/ethernet/hisilicon/hns/hnae.h b/drivers/net/ethernet/hisilicon/hns/hnae.h index fa5b30f547f6620a6e761860be6afa341dc185c8..08a750fb60c49d397c61845130e153fe1e3b0b3e 100644 --- a/drivers/net/ethernet/hisilicon/hns/hnae.h +++ b/drivers/net/ethernet/hisilicon/hns/hnae.h @@ -220,10 +220,10 @@ struct hnae_desc_cb { /* priv data for the desc, e.g. skb when use with ip stack*/ void *priv; - u16 page_offset; - u16 reuse_flag; + u32 page_offset; + u32 length; /* length of the buffer */ - u16 length; /* length of the buffer */ + u16 reuse_flag; /* desc type, used by the ring user to mark the type of the priv data */ u16 type; @@ -486,6 +486,8 @@ struct hnae_ae_ops { u8 *auto_neg, u16 *speed, u8 *duplex); void (*toggle_ring_irq)(struct hnae_ring *ring, u32 val); void (*adjust_link)(struct hnae_handle *handle, int speed, int duplex); + bool (*need_adjust_link)(struct hnae_handle *handle, + int speed, int duplex); int (*set_loopback)(struct hnae_handle *handle, enum hnae_loop loop_mode, int en); void (*get_ring_bdnum_limit)(struct hnae_queue *queue, diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c index bd68379d2beab60415cf5d071e598b36fd9871ed..bf930ab3c2bde092b574105ce3858844de1e7814 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c @@ -155,6 +155,41 @@ static void hns_ae_put_handle(struct hnae_handle *handle) hns_ae_get_ring_pair(handle->qs[i])->used_by_vf = 0; } +static int hns_ae_wait_flow_down(struct hnae_handle *handle) +{ + struct dsaf_device *dsaf_dev; + struct hns_ppe_cb *ppe_cb; + struct hnae_vf_cb *vf_cb; + int ret; + int i; + + for (i = 0; i < handle->q_num; i++) { + ret = hns_rcb_wait_tx_ring_clean(handle->qs[i]); + if (ret) + return ret; + } + + ppe_cb = hns_get_ppe_cb(handle); + ret = hns_ppe_wait_tx_fifo_clean(ppe_cb); + if (ret) + return ret; + + dsaf_dev = hns_ae_get_dsaf_dev(handle->dev); + if (!dsaf_dev) + return -EINVAL; + ret = hns_dsaf_wait_pkt_clean(dsaf_dev, handle->dport_id); + if (ret) + return ret; + + vf_cb = hns_ae_get_vf_cb(handle); + ret = hns_mac_wait_fifo_clean(vf_cb->mac_cb); + if (ret) + return ret; + + mdelay(10); + return 0; +} + static void hns_ae_ring_enable_all(struct hnae_handle *handle, int val) { int q_num = handle->q_num; @@ -399,12 +434,41 @@ static int hns_ae_get_mac_info(struct hnae_handle *handle, return hns_mac_get_port_info(mac_cb, auto_neg, speed, duplex); } +static bool hns_ae_need_adjust_link(struct hnae_handle *handle, int speed, + int duplex) +{ + struct hns_mac_cb *mac_cb = hns_get_mac_cb(handle); + + return hns_mac_need_adjust_link(mac_cb, speed, duplex); +} + static void hns_ae_adjust_link(struct hnae_handle *handle, int speed, int duplex) { struct hns_mac_cb *mac_cb = hns_get_mac_cb(handle); - hns_mac_adjust_link(mac_cb, speed, duplex); + switch (mac_cb->dsaf_dev->dsaf_ver) { + case AE_VERSION_1: + hns_mac_adjust_link(mac_cb, speed, duplex); + break; + + case AE_VERSION_2: + /* chip need to clear all pkt inside */ + hns_mac_disable(mac_cb, MAC_COMM_MODE_RX); + if (hns_ae_wait_flow_down(handle)) { + hns_mac_enable(mac_cb, MAC_COMM_MODE_RX); + break; + } + + hns_mac_adjust_link(mac_cb, speed, duplex); + hns_mac_enable(mac_cb, MAC_COMM_MODE_RX); + break; + + default: + break; + } + + return; } static void hns_ae_get_ring_bdnum_limit(struct hnae_queue *queue, @@ -902,6 +966,7 @@ static struct hnae_ae_ops hns_dsaf_ops = { .get_status = hns_ae_get_link_status, .get_info = hns_ae_get_mac_info, .adjust_link = hns_ae_adjust_link, + .need_adjust_link = hns_ae_need_adjust_link, .set_loopback = hns_ae_config_loopback, .get_ring_bdnum_limit = hns_ae_get_ring_bdnum_limit, .get_pauseparam = hns_ae_get_pauseparam, diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c index 74bd260ca02a887869a507f8746dfc928522d4be..8c7bc5cf193c33fb17dc96477f25f7c176267ced 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c @@ -257,6 +257,16 @@ static void hns_gmac_get_pausefrm_cfg(void *mac_drv, u32 *rx_pause_en, *tx_pause_en = dsaf_get_bit(pause_en, GMAC_PAUSE_EN_TX_FDFC_B); } +static bool hns_gmac_need_adjust_link(void *mac_drv, enum mac_speed speed, + int duplex) +{ + struct mac_driver *drv = (struct mac_driver *)mac_drv; + struct hns_mac_cb *mac_cb = drv->mac_cb; + + return (mac_cb->speed != speed) || + (mac_cb->half_duplex == duplex); +} + static int hns_gmac_adjust_link(void *mac_drv, enum mac_speed speed, u32 full_duplex) { @@ -309,6 +319,30 @@ static void hns_gmac_set_promisc(void *mac_drv, u8 en) hns_gmac_set_uc_match(mac_drv, en); } +int hns_gmac_wait_fifo_clean(void *mac_drv) +{ + struct mac_driver *drv = (struct mac_driver *)mac_drv; + int wait_cnt; + u32 val; + + wait_cnt = 0; + while (wait_cnt++ < HNS_MAX_WAIT_CNT) { + val = dsaf_read_dev(drv, GMAC_FIFO_STATE_REG); + /* bit5~bit0 is not send complete pkts */ + if ((val & 0x3f) == 0) + break; + usleep_range(100, 200); + } + + if (wait_cnt >= HNS_MAX_WAIT_CNT) { + dev_err(drv->dev, + "hns ge %d fifo was not idle.\n", drv->mac_id); + return -EBUSY; + } + + return 0; +} + static void hns_gmac_init(void *mac_drv) { u32 port; @@ -690,6 +724,7 @@ void *hns_gmac_config(struct hns_mac_cb *mac_cb, struct mac_params *mac_param) mac_drv->mac_disable = hns_gmac_disable; mac_drv->mac_free = hns_gmac_free; mac_drv->adjust_link = hns_gmac_adjust_link; + mac_drv->need_adjust_link = hns_gmac_need_adjust_link; mac_drv->set_tx_auto_pause_frames = hns_gmac_set_tx_auto_pause_frames; mac_drv->config_max_frame_length = hns_gmac_config_max_frame_length; mac_drv->mac_pausefrm_cfg = hns_gmac_pause_frm_cfg; @@ -717,6 +752,7 @@ void *hns_gmac_config(struct hns_mac_cb *mac_cb, struct mac_params *mac_param) mac_drv->get_strings = hns_gmac_get_strings; mac_drv->update_stats = hns_gmac_update_stats; mac_drv->set_promiscuous = hns_gmac_set_promisc; + mac_drv->wait_fifo_clean = hns_gmac_wait_fifo_clean; return (void *)mac_drv; } diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c index 8b5cdf490850374baba82205264967c8f12a50e5..5a8dbd72fe45c8ab2819689c92e87e2bb9ae4c6e 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c @@ -114,6 +114,26 @@ int hns_mac_get_port_info(struct hns_mac_cb *mac_cb, return 0; } +/** + *hns_mac_is_adjust_link - check is need change mac speed and duplex register + *@mac_cb: mac device + *@speed: phy device speed + *@duplex:phy device duplex + * + */ +bool hns_mac_need_adjust_link(struct hns_mac_cb *mac_cb, int speed, int duplex) +{ + struct mac_driver *mac_ctrl_drv; + + mac_ctrl_drv = (struct mac_driver *)(mac_cb->priv.mac); + + if (mac_ctrl_drv->need_adjust_link) + return mac_ctrl_drv->need_adjust_link(mac_ctrl_drv, + (enum mac_speed)speed, duplex); + else + return true; +} + void hns_mac_adjust_link(struct hns_mac_cb *mac_cb, int speed, int duplex) { int ret; @@ -432,6 +452,16 @@ int hns_mac_vm_config_bc_en(struct hns_mac_cb *mac_cb, u32 vmid, bool enable) return 0; } +int hns_mac_wait_fifo_clean(struct hns_mac_cb *mac_cb) +{ + struct mac_driver *drv = hns_mac_get_drv(mac_cb); + + if (drv->wait_fifo_clean) + return drv->wait_fifo_clean(drv); + + return 0; +} + void hns_mac_reset(struct hns_mac_cb *mac_cb) { struct mac_driver *drv = hns_mac_get_drv(mac_cb); @@ -1001,6 +1031,20 @@ static int hns_mac_get_max_port_num(struct dsaf_device *dsaf_dev) return DSAF_MAX_PORT_NUM; } +void hns_mac_enable(struct hns_mac_cb *mac_cb, enum mac_commom_mode mode) +{ + struct mac_driver *mac_ctrl_drv = hns_mac_get_drv(mac_cb); + + mac_ctrl_drv->mac_enable(mac_cb->priv.mac, mode); +} + +void hns_mac_disable(struct hns_mac_cb *mac_cb, enum mac_commom_mode mode) +{ + struct mac_driver *mac_ctrl_drv = hns_mac_get_drv(mac_cb); + + mac_ctrl_drv->mac_disable(mac_cb->priv.mac, mode); +} + /** * hns_mac_init - init mac * @dsaf_dev: dsa fabric device struct pointer diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h index bbc0a98e7ca3260c7f8b1b8cb7f7f203860bfdce..fbc75341bef760b82a1d7a10469d5649db91e366 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h @@ -356,6 +356,9 @@ struct mac_driver { /*adjust mac mode of port,include speed and duplex*/ int (*adjust_link)(void *mac_drv, enum mac_speed speed, u32 full_duplex); + /* need adjust link */ + bool (*need_adjust_link)(void *mac_drv, enum mac_speed speed, + int duplex); /* config autoegotaite mode of port*/ void (*set_an_mode)(void *mac_drv, u8 enable); /* config loopbank mode */ @@ -394,6 +397,7 @@ struct mac_driver { void (*get_info)(void *mac_drv, struct mac_info *mac_info); void (*update_stats)(void *mac_drv); + int (*wait_fifo_clean)(void *mac_drv); enum mac_mode mac_mode; u8 mac_id; @@ -427,6 +431,7 @@ void *hns_xgmac_config(struct hns_mac_cb *mac_cb, int hns_mac_init(struct dsaf_device *dsaf_dev); void mac_adjust_link(struct net_device *net_dev); +bool hns_mac_need_adjust_link(struct hns_mac_cb *mac_cb, int speed, int duplex); void hns_mac_get_link_status(struct hns_mac_cb *mac_cb, u32 *link_status); int hns_mac_change_vf_addr(struct hns_mac_cb *mac_cb, u32 vmid, char *addr); int hns_mac_set_multi(struct hns_mac_cb *mac_cb, @@ -463,5 +468,8 @@ int hns_mac_add_uc_addr(struct hns_mac_cb *mac_cb, u8 vf_id, int hns_mac_rm_uc_addr(struct hns_mac_cb *mac_cb, u8 vf_id, const unsigned char *addr); int hns_mac_clr_multicast(struct hns_mac_cb *mac_cb, int vfn); +void hns_mac_enable(struct hns_mac_cb *mac_cb, enum mac_commom_mode mode); +void hns_mac_disable(struct hns_mac_cb *mac_cb, enum mac_commom_mode mode); +int hns_mac_wait_fifo_clean(struct hns_mac_cb *mac_cb); #endif /* _HNS_DSAF_MAC_H */ diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c index e0bc79ea3d88091c5723403c724a5d4460f93e99..1f056a6b167e7a1c7a19e5c94079131567bb7302 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c @@ -2720,6 +2720,35 @@ void hns_dsaf_set_promisc_tcam(struct dsaf_device *dsaf_dev, soft_mac_entry->index = enable ? entry_index : DSAF_INVALID_ENTRY_IDX; } +int hns_dsaf_wait_pkt_clean(struct dsaf_device *dsaf_dev, int port) +{ + u32 val, val_tmp; + int wait_cnt; + + if (port >= DSAF_SERVICE_NW_NUM) + return 0; + + wait_cnt = 0; + while (wait_cnt++ < HNS_MAX_WAIT_CNT) { + val = dsaf_read_dev(dsaf_dev, DSAF_VOQ_IN_PKT_NUM_0_REG + + (port + DSAF_XGE_NUM) * 0x40); + val_tmp = dsaf_read_dev(dsaf_dev, DSAF_VOQ_OUT_PKT_NUM_0_REG + + (port + DSAF_XGE_NUM) * 0x40); + if (val == val_tmp) + break; + + usleep_range(100, 200); + } + + if (wait_cnt >= HNS_MAX_WAIT_CNT) { + dev_err(dsaf_dev->dev, "hns dsaf clean wait timeout(%u - %u).\n", + val, val_tmp); + return -EBUSY; + } + + return 0; +} + /** * dsaf_probe - probo dsaf dev * @pdev: dasf platform device diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h index 4507e8222683c112c05eeca4633e65990b789b8f..0e1cd99831a6083faa790aa80be1f6c635b15a50 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h @@ -44,6 +44,8 @@ struct hns_mac_cb; #define DSAF_ROCE_CREDIT_CHN 8 #define DSAF_ROCE_CHAN_MODE 3 +#define HNS_MAX_WAIT_CNT 10000 + enum dsaf_roce_port_mode { DSAF_ROCE_6PORT_MODE, DSAF_ROCE_4PORT_MODE, @@ -463,5 +465,6 @@ int hns_dsaf_rm_mac_addr( int hns_dsaf_clr_mac_mc_port(struct dsaf_device *dsaf_dev, u8 mac_id, u8 port_num); +int hns_dsaf_wait_pkt_clean(struct dsaf_device *dsaf_dev, int port); #endif /* __HNS_DSAF_MAIN_H__ */ diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c index 93e71e27401b4da815e899753dc7be1a83ff3f14..a19932aeb9d7e67f01535a04ad8ab4fddf14f61d 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c @@ -274,6 +274,29 @@ static void hns_ppe_exc_irq_en(struct hns_ppe_cb *ppe_cb, int en) dsaf_write_dev(ppe_cb, PPE_INTEN_REG, msk_vlue & vld_msk); } +int hns_ppe_wait_tx_fifo_clean(struct hns_ppe_cb *ppe_cb) +{ + int wait_cnt; + u32 val; + + wait_cnt = 0; + while (wait_cnt++ < HNS_MAX_WAIT_CNT) { + val = dsaf_read_dev(ppe_cb, PPE_CURR_TX_FIFO0_REG) & 0x3ffU; + if (!val) + break; + + usleep_range(100, 200); + } + + if (wait_cnt >= HNS_MAX_WAIT_CNT) { + dev_err(ppe_cb->dev, "hns ppe tx fifo clean wait timeout, still has %u pkt.\n", + val); + return -EBUSY; + } + + return 0; +} + /** * ppe_init_hw - init ppe * @ppe_cb: ppe device diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h index 9d8e643e8aa6ff518ab68d4af4c42d292a37ae47..f670e63a5a018cd5b48b4a62093c104905aa4463 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h @@ -100,6 +100,7 @@ struct ppe_common_cb { }; +int hns_ppe_wait_tx_fifo_clean(struct hns_ppe_cb *ppe_cb); int hns_ppe_init(struct dsaf_device *dsaf_dev); void hns_ppe_uninit(struct dsaf_device *dsaf_dev); diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c index e2e28532e4dc2d03cf15330c621f8fb49469e382..1e43d7a3ca868654bb56b96706d5546bfaf1e1a2 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c @@ -66,6 +66,29 @@ void hns_rcb_wait_fbd_clean(struct hnae_queue **qs, int q_num, u32 flag) "queue(%d) wait fbd(%d) clean fail!!\n", i, fbd_num); } +int hns_rcb_wait_tx_ring_clean(struct hnae_queue *qs) +{ + u32 head, tail; + int wait_cnt; + + tail = dsaf_read_dev(&qs->tx_ring, RCB_REG_TAIL); + wait_cnt = 0; + while (wait_cnt++ < HNS_MAX_WAIT_CNT) { + head = dsaf_read_dev(&qs->tx_ring, RCB_REG_HEAD); + if (tail == head) + break; + + usleep_range(100, 200); + } + + if (wait_cnt >= HNS_MAX_WAIT_CNT) { + dev_err(qs->dev->dev, "rcb wait timeout, head not equal to tail.\n"); + return -EBUSY; + } + + return 0; +} + /** *hns_rcb_reset_ring_hw - ring reset *@q: ring struct pointer diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.h index 602816498c8dd0c4aecd20ae9f5df196d7944821..2319b772a271e519d6a69a0976713a19c60f4a8a 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.h @@ -136,6 +136,7 @@ void hns_rcbv2_int_clr_hw(struct hnae_queue *q, u32 flag); void hns_rcb_init_hw(struct ring_pair_cb *ring); void hns_rcb_reset_ring_hw(struct hnae_queue *q); void hns_rcb_wait_fbd_clean(struct hnae_queue **qs, int q_num, u32 flag); +int hns_rcb_wait_tx_ring_clean(struct hnae_queue *qs); u32 hns_rcb_get_rx_coalesced_frames( struct rcb_common_cb *rcb_common, u32 port_idx); u32 hns_rcb_get_tx_coalesced_frames( diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h index 46a52d9bb196326e5da7481f43616dab0afd12a2..6d20e4eb7402c2254caec573b4e40eae4df7a9a2 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h @@ -464,6 +464,7 @@ #define RCB_RING_INTMSK_TX_OVERTIME_REG 0x000C4 #define RCB_RING_INTSTS_TX_OVERTIME_REG 0x000C8 +#define GMAC_FIFO_STATE_REG 0x0000UL #define GMAC_DUPLEX_TYPE_REG 0x0008UL #define GMAC_FD_FC_TYPE_REG 0x000CUL #define GMAC_TX_WATER_LINE_REG 0x0010UL diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c index e77192683dbad9a1fca22816e411abf4c3c25d8c..07d6a9cf2c5563a8c2554ab780e2de3eb89f2230 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c @@ -530,7 +530,7 @@ static void hns_nic_reuse_page(struct sk_buff *skb, int i, } skb_add_rx_frag(skb, i, desc_cb->priv, desc_cb->page_offset + pull_len, - size - pull_len, truesize - pull_len); + size - pull_len, truesize); /* avoid re-using remote pages,flag default unreuse */ if (unlikely(page_to_nid(desc_cb->priv) != numa_node_id())) @@ -1212,11 +1212,26 @@ static void hns_nic_adjust_link(struct net_device *ndev) struct hnae_handle *h = priv->ae_handle; int state = 1; + /* If there is no phy, do not need adjust link */ if (ndev->phydev) { - h->dev->ops->adjust_link(h, ndev->phydev->speed, - ndev->phydev->duplex); - state = ndev->phydev->link; + /* When phy link down, do nothing */ + if (ndev->phydev->link == 0) + return; + + if (h->dev->ops->need_adjust_link(h, ndev->phydev->speed, + ndev->phydev->duplex)) { + /* because Hi161X chip don't support to change gmac + * speed and duplex with traffic. Delay 200ms to + * make sure there is no more data in chip FIFO. + */ + netif_carrier_off(ndev); + msleep(200); + h->dev->ops->adjust_link(h, ndev->phydev->speed, + ndev->phydev->duplex); + netif_carrier_on(ndev); + } } + state = state && h->dev->ops->get_status(h); if (state != priv->link) { diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c index 2e14a3ae1d8be0f9841a5c53f456c4d2e4f4d270..c1e947bb852ff888b02505abcf09987f86f4ac06 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c @@ -243,7 +243,9 @@ static int hns_nic_set_link_ksettings(struct net_device *net_dev, } if (h->dev->ops->adjust_link) { + netif_carrier_off(net_dev); h->dev->ops->adjust_link(h, (int)speed, cmd->base.duplex); + netif_carrier_on(net_dev); return 0; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index c133491ad9fa0ab3e5bbd3a5356ff64e8e856627..654aad6e748bdb7d23b8ec3dae875c95d73548fd 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -3105,7 +3105,7 @@ static bool hclge_is_all_function_id_zero(struct hclge_desc *desc) #define HCLGE_FUNC_NUMBER_PER_DESC 6 int i, j; - for (i = 0; i < HCLGE_DESC_NUMBER; i++) + for (i = 1; i < HCLGE_DESC_NUMBER; i++) for (j = 0; j < HCLGE_FUNC_NUMBER_PER_DESC; j++) if (desc[i].data[j]) return false; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c index f32d719c4f77a2bf4dfd00896250aa27cc29f78c..8f90dd1be6b593e808b466abbd948e8899773ba3 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c @@ -187,6 +187,8 @@ int hclge_mac_start_phy(struct hclge_dev *hdev) if (!phydev) return 0; + phydev->supported &= ~SUPPORTED_FIBRE; + ret = phy_connect_direct(netdev, phydev, hclge_mac_adjust_link, PHY_INTERFACE_MODE_SGMII); diff --git a/drivers/net/ethernet/hp/hp100.c b/drivers/net/ethernet/hp/hp100.c index c8c7ad2eff77ecb5f2bd4ee5012a41b3ac1afcc8..9b5a68b6543287a93107ae2a923ee3bf99a38a82 100644 --- a/drivers/net/ethernet/hp/hp100.c +++ b/drivers/net/ethernet/hp/hp100.c @@ -2634,7 +2634,7 @@ static int hp100_login_to_vg_hub(struct net_device *dev, u_short force_relogin) /* Wait for link to drop */ time = jiffies + (HZ / 10); do { - if (~(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST)) + if (!(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST)) break; if (!in_interrupt()) schedule_timeout_interruptible(1); diff --git a/drivers/net/ethernet/huawei/hinic/hinic_main.c b/drivers/net/ethernet/huawei/hinic/hinic_main.c index eb53bd93065e0da12ddd744feffdd34f853c952e..a696b5b2d40e6bb72bb4cd7663d8f84ea49588ff 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_main.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_main.c @@ -981,6 +981,7 @@ static int nic_dev_init(struct pci_dev *pdev) hinic_hwdev_cb_register(nic_dev->hwdev, HINIC_MGMT_MSG_CMD_LINK_STATUS, nic_dev, link_status_event_handler); + SET_NETDEV_DEV(netdev, &pdev->dev); err = register_netdev(netdev); if (err) { dev_err(&pdev->dev, "Failed to register netdev\n"); diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 98493be7b4afedf1ad367ba6b21155ddcb25478b..046af22a37cbc13938ac4d1de2c33a63babc5368 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -1463,8 +1463,8 @@ static int do_reset(struct ibmvnic_adapter *adapter, rc = ibmvnic_login(netdev); if (rc) { - adapter->state = VNIC_PROBED; - return 0; + adapter->state = reset_state; + return rc; } rc = reset_tx_pools(adapter); diff --git a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c index 3b3983a1ffbba1d6795ead832c5aceb801023969..10df2d60c1814b91b1a282a2a44a7ddc39a8300c 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c +++ b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c @@ -644,14 +644,14 @@ static int e1000_set_ringparam(struct net_device *netdev, adapter->tx_ring = tx_old; e1000_free_all_rx_resources(adapter); e1000_free_all_tx_resources(adapter); - kfree(tx_old); - kfree(rx_old); adapter->rx_ring = rxdr; adapter->tx_ring = txdr; err = e1000_up(adapter); if (err) goto err_setup; } + kfree(tx_old); + kfree(rx_old); clear_bit(__E1000_RESETTING, &adapter->flags); return 0; @@ -664,7 +664,8 @@ static int e1000_set_ringparam(struct net_device *netdev, err_alloc_rx: kfree(txdr); err_alloc_tx: - e1000_up(adapter); + if (netif_running(adapter->netdev)) + e1000_up(adapter); err_setup: clear_bit(__E1000_RESETTING, &adapter->flags); return err; diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h index afb7ebe20b2438e9500f5dff2b1126ccde9c4670..824fd44e25f0d694a20bed7733dfebfaff9d0195 100644 --- a/drivers/net/ethernet/intel/e1000e/defines.h +++ b/drivers/net/ethernet/intel/e1000e/defines.h @@ -400,6 +400,10 @@ #define E1000_ICR_RXDMT0 0x00000010 /* Rx desc min. threshold (0) */ #define E1000_ICR_RXO 0x00000040 /* Receiver Overrun */ #define E1000_ICR_RXT0 0x00000080 /* Rx timer intr (ring 0) */ +#define E1000_ICR_MDAC 0x00000200 /* MDIO Access Complete */ +#define E1000_ICR_SRPD 0x00010000 /* Small Receive Packet Detected */ +#define E1000_ICR_ACK 0x00020000 /* Receive ACK Frame Detected */ +#define E1000_ICR_MNG 0x00040000 /* Manageability Event Detected */ #define E1000_ICR_ECCER 0x00400000 /* Uncorrectable ECC Error */ /* If this bit asserted, the driver should claim the interrupt */ #define E1000_ICR_INT_ASSERTED 0x80000000 @@ -407,7 +411,7 @@ #define E1000_ICR_RXQ1 0x00200000 /* Rx Queue 1 Interrupt */ #define E1000_ICR_TXQ0 0x00400000 /* Tx Queue 0 Interrupt */ #define E1000_ICR_TXQ1 0x00800000 /* Tx Queue 1 Interrupt */ -#define E1000_ICR_OTHER 0x01000000 /* Other Interrupts */ +#define E1000_ICR_OTHER 0x01000000 /* Other Interrupt */ /* PBA ECC Register */ #define E1000_PBA_ECC_COUNTER_MASK 0xFFF00000 /* ECC counter mask */ @@ -431,12 +435,27 @@ E1000_IMS_RXSEQ | \ E1000_IMS_LSC) +/* These are all of the events related to the OTHER interrupt. + */ +#define IMS_OTHER_MASK ( \ + E1000_IMS_LSC | \ + E1000_IMS_RXO | \ + E1000_IMS_MDAC | \ + E1000_IMS_SRPD | \ + E1000_IMS_ACK | \ + E1000_IMS_MNG) + /* Interrupt Mask Set */ #define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ #define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */ #define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* Rx sequence error */ #define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* Rx desc min. threshold */ +#define E1000_IMS_RXO E1000_ICR_RXO /* Receiver Overrun */ #define E1000_IMS_RXT0 E1000_ICR_RXT0 /* Rx timer intr */ +#define E1000_IMS_MDAC E1000_ICR_MDAC /* MDIO Access Complete */ +#define E1000_IMS_SRPD E1000_ICR_SRPD /* Small Receive Packet */ +#define E1000_IMS_ACK E1000_ICR_ACK /* Receive ACK Frame Detected */ +#define E1000_IMS_MNG E1000_ICR_MNG /* Manageability Event */ #define E1000_IMS_ECCER E1000_ICR_ECCER /* Uncorrectable ECC Error */ #define E1000_IMS_RXQ0 E1000_ICR_RXQ0 /* Rx Queue 0 Interrupt */ #define E1000_IMS_RXQ1 E1000_ICR_RXQ1 /* Rx Queue 1 Interrupt */ diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index ff308b05d68cc91efa7b195db9952d368553557f..00eedf202e62da10eec8ecf310fa1f689aaa0e57 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -1367,9 +1367,6 @@ static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force) * Checks to see of the link status of the hardware has changed. If a * change in link status has been detected, then we read the PHY registers * to get the current speed/duplex if link exists. - * - * Returns a negative error code (-E1000_ERR_*) or 0 (link down) or 1 (link - * up). **/ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) { @@ -1385,7 +1382,8 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) * Change or Rx Sequence Error interrupt. */ if (!mac->get_link_status) - return 1; + return 0; + mac->get_link_status = false; /* First we want to see if the MII Status Register reports * link. If so, then we want to get the current speed/duplex @@ -1393,12 +1391,12 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) */ ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); if (ret_val) - return ret_val; + goto out; if (hw->mac.type == e1000_pchlan) { ret_val = e1000_k1_gig_workaround_hv(hw, link); if (ret_val) - return ret_val; + goto out; } /* When connected at 10Mbps half-duplex, some parts are excessively @@ -1431,7 +1429,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) ret_val = hw->phy.ops.acquire(hw); if (ret_val) - return ret_val; + goto out; if (hw->mac.type == e1000_pch2lan) emi_addr = I82579_RX_CONFIG; @@ -1453,7 +1451,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) hw->phy.ops.release(hw); if (ret_val) - return ret_val; + goto out; if (hw->mac.type >= e1000_pch_spt) { u16 data; @@ -1462,14 +1460,14 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) if (speed == SPEED_1000) { ret_val = hw->phy.ops.acquire(hw); if (ret_val) - return ret_val; + goto out; ret_val = e1e_rphy_locked(hw, PHY_REG(776, 20), &data); if (ret_val) { hw->phy.ops.release(hw); - return ret_val; + goto out; } ptr_gap = (data & (0x3FF << 2)) >> 2; @@ -1483,18 +1481,18 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) } hw->phy.ops.release(hw); if (ret_val) - return ret_val; + goto out; } else { ret_val = hw->phy.ops.acquire(hw); if (ret_val) - return ret_val; + goto out; ret_val = e1e_wphy_locked(hw, PHY_REG(776, 20), 0xC023); hw->phy.ops.release(hw); if (ret_val) - return ret_val; + goto out; } } @@ -1521,7 +1519,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_V3)) { ret_val = e1000_k1_workaround_lpt_lp(hw, link); if (ret_val) - return ret_val; + goto out; } if (hw->mac.type >= e1000_pch_lpt) { /* Set platform power management values for @@ -1529,7 +1527,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) */ ret_val = e1000_platform_pm_pch_lpt(hw, link); if (ret_val) - return ret_val; + goto out; } /* Clear link partner's EEE ability */ @@ -1552,9 +1550,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) } if (!link) - return 0; /* No link detected */ - - mac->get_link_status = false; + goto out; switch (hw->mac.type) { case e1000_pch2lan: @@ -1616,12 +1612,14 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) * different link partner. */ ret_val = e1000e_config_fc_after_link_up(hw); - if (ret_val) { + if (ret_val) e_dbg("Error configuring flow control\n"); - return ret_val; - } - return 1; + return ret_val; + +out: + mac->get_link_status = true; + return ret_val; } static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter) diff --git a/drivers/net/ethernet/intel/e1000e/mac.c b/drivers/net/ethernet/intel/e1000e/mac.c index db735644b31214e8c35216d35642531c713abbb1..48cc945fc8b0f96e62d5066ba63b136718ce73d7 100644 --- a/drivers/net/ethernet/intel/e1000e/mac.c +++ b/drivers/net/ethernet/intel/e1000e/mac.c @@ -410,9 +410,6 @@ void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw) * Checks to see of the link status of the hardware has changed. If a * change in link status has been detected, then we read the PHY registers * to get the current speed/duplex if link exists. - * - * Returns a negative error code (-E1000_ERR_*) or 0 (link down) or 1 (link - * up). **/ s32 e1000e_check_for_copper_link(struct e1000_hw *hw) { @@ -426,20 +423,16 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw) * Change or Rx Sequence Error interrupt. */ if (!mac->get_link_status) - return 1; + return 0; + mac->get_link_status = false; /* First we want to see if the MII Status Register reports * link. If so, then we want to get the current speed/duplex * of the PHY. */ ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); - if (ret_val) - return ret_val; - - if (!link) - return 0; /* No link detected */ - - mac->get_link_status = false; + if (ret_val || !link) + goto out; /* Check if there was DownShift, must be checked * immediately after link-up @@ -464,12 +457,14 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw) * different link partner. */ ret_val = e1000e_config_fc_after_link_up(hw); - if (ret_val) { + if (ret_val) e_dbg("Error configuring flow control\n"); - return ret_val; - } - return 1; + return ret_val; + +out: + mac->get_link_status = true; + return ret_val; } /** diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 6265ce8915b66132f4e8aee12388491b517b8689..a25dc581a9030a8391bee1a630a36d6ba0057eba 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -1910,30 +1910,20 @@ static irqreturn_t e1000_msix_other(int __always_unused irq, void *data) struct net_device *netdev = data; struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - u32 icr; - bool enable = true; - - icr = er32(ICR); - if (icr & E1000_ICR_RXO) { - ew32(ICR, E1000_ICR_RXO); - enable = false; - /* napi poll will re-enable Other, make sure it runs */ - if (napi_schedule_prep(&adapter->napi)) { - adapter->total_rx_bytes = 0; - adapter->total_rx_packets = 0; - __napi_schedule(&adapter->napi); - } - } + u32 icr = er32(ICR); + + if (icr & adapter->eiac_mask) + ew32(ICS, (icr & adapter->eiac_mask)); + if (icr & E1000_ICR_LSC) { - ew32(ICR, E1000_ICR_LSC); hw->mac.get_link_status = true; /* guard against interrupt when we're going down */ if (!test_bit(__E1000_DOWN, &adapter->state)) mod_timer(&adapter->watchdog_timer, jiffies + 1); } - if (enable && !test_bit(__E1000_DOWN, &adapter->state)) - ew32(IMS, E1000_IMS_OTHER); + if (!test_bit(__E1000_DOWN, &adapter->state)) + ew32(IMS, E1000_IMS_OTHER | IMS_OTHER_MASK); return IRQ_HANDLED; } @@ -2036,7 +2026,6 @@ static void e1000_configure_msix(struct e1000_adapter *adapter) hw->hw_addr + E1000_EITR_82574(vector)); else writel(1, hw->hw_addr + E1000_EITR_82574(vector)); - adapter->eiac_mask |= E1000_IMS_OTHER; /* Cause Tx interrupts on every write back */ ivar |= BIT(31); @@ -2261,7 +2250,8 @@ static void e1000_irq_enable(struct e1000_adapter *adapter) if (adapter->msix_entries) { ew32(EIAC_82574, adapter->eiac_mask & E1000_EIAC_MASK_82574); - ew32(IMS, adapter->eiac_mask | E1000_IMS_LSC); + ew32(IMS, adapter->eiac_mask | E1000_IMS_OTHER | + IMS_OTHER_MASK); } else if (hw->mac.type >= e1000_pch_lpt) { ew32(IMS, IMS_ENABLE_MASK | E1000_IMS_ECCER); } else { @@ -2703,8 +2693,7 @@ static int e1000e_poll(struct napi_struct *napi, int weight) napi_complete_done(napi, work_done); if (!test_bit(__E1000_DOWN, &adapter->state)) { if (adapter->msix_entries) - ew32(IMS, adapter->rx_ring->ims_val | - E1000_IMS_OTHER); + ew32(IMS, adapter->rx_ring->ims_val); else e1000_irq_enable(adapter); } @@ -5100,7 +5089,7 @@ static bool e1000e_has_link(struct e1000_adapter *adapter) case e1000_media_type_copper: if (hw->mac.get_link_status) { ret_val = hw->mac.ops.check_for_link(hw); - link_active = ret_val > 0; + link_active = !hw->mac.get_link_status; } else { link_active = true; } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index 64429a14c630f09a2aa4d370d10239046c373d08..815284fe93241ef29cb941465009f07323d9c8b4 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -1895,7 +1895,12 @@ s32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq, if (enable_addr != 0) rar_high |= IXGBE_RAH_AV; + /* Record lower 32 bits of MAC address and then make + * sure that write is flushed to hardware before writing + * the upper 16 bits and setting the valid bit. + */ IXGBE_WRITE_REG(hw, IXGBE_RAL(index), rar_low); + IXGBE_WRITE_FLUSH(hw); IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high); return 0; @@ -1927,8 +1932,13 @@ s32 ixgbe_clear_rar_generic(struct ixgbe_hw *hw, u32 index) rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(index)); rar_high &= ~(0x0000FFFF | IXGBE_RAH_AV); - IXGBE_WRITE_REG(hw, IXGBE_RAL(index), 0); + /* Clear the address valid bit and upper 16 bits of the address + * before clearing the lower bits. This way we aren't updating + * a live filter. + */ IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high); + IXGBE_WRITE_FLUSH(hw); + IXGBE_WRITE_REG(hw, IXGBE_RAL(index), 0); /* clear VMDq pool/queue selection for this RAR */ hw->mac.ops.clear_vmdq(hw, index, IXGBE_CLEAR_VMDQ_ALL); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index b68d94b49a8a690416eb9e44db7301906ce07327..42183a8b649c7fe7ca2fdfeff80e707401a56e77 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -3108,11 +3108,13 @@ int ixgbe_poll(struct napi_struct *napi, int budget) return budget; /* all work done, exit the polling mode */ - napi_complete_done(napi, work_done); - if (adapter->rx_itr_setting & 1) - ixgbe_set_itr(q_vector); - if (!test_bit(__IXGBE_DOWN, &adapter->state)) - ixgbe_irq_enable_queues(adapter, BIT_ULL(q_vector->v_idx)); + if (likely(napi_complete_done(napi, work_done))) { + if (adapter->rx_itr_setting & 1) + ixgbe_set_itr(q_vector); + if (!test_bit(__IXGBE_DOWN, &adapter->state)) + ixgbe_irq_enable_queues(adapter, + BIT_ULL(q_vector->v_idx)); + } return min(work_done, budget - 1); } diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 3deaa341331370bf7e88e8e3583d7b4f0fd2b104..074a5b79d691318a3bd2bde35dcb3a5ee93df0ab 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -3195,7 +3195,6 @@ static int mvneta_change_mtu(struct net_device *dev, int mtu) on_each_cpu(mvneta_percpu_enable, pp, true); mvneta_start_dev(pp); - mvneta_port_up(pp); netdev_update_features(dev); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index cf94fdf25155f9882eb3d5d3395644a22259b982..c7654209668bdebbbb969af753ca54298fabdde0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -449,6 +449,7 @@ const char *mlx5_command_str(int command) MLX5_COMMAND_STR_CASE(SET_HCA_CAP); MLX5_COMMAND_STR_CASE(QUERY_ISSI); MLX5_COMMAND_STR_CASE(SET_ISSI); + MLX5_COMMAND_STR_CASE(SET_DRIVER_VERSION); MLX5_COMMAND_STR_CASE(CREATE_MKEY); MLX5_COMMAND_STR_CASE(QUERY_MKEY); MLX5_COMMAND_STR_CASE(DESTROY_MKEY); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dev.c b/drivers/net/ethernet/mellanox/mlx5/core/dev.c index 17b723218b0c0d891a44379e0f69ad804d43c154..07fda3984e102cc49701eb2249b929b2550e4173 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/dev.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/dev.c @@ -132,11 +132,11 @@ void mlx5_add_device(struct mlx5_interface *intf, struct mlx5_priv *priv) delayed_event_start(priv); dev_ctx->context = intf->add(dev); - set_bit(MLX5_INTERFACE_ADDED, &dev_ctx->state); - if (intf->attach) - set_bit(MLX5_INTERFACE_ATTACHED, &dev_ctx->state); - if (dev_ctx->context) { + set_bit(MLX5_INTERFACE_ADDED, &dev_ctx->state); + if (intf->attach) + set_bit(MLX5_INTERFACE_ATTACHED, &dev_ctx->state); + spin_lock_irq(&priv->ctx_lock); list_add_tail(&dev_ctx->list, &priv->ctx_list); @@ -211,12 +211,17 @@ static void mlx5_attach_interface(struct mlx5_interface *intf, struct mlx5_priv if (intf->attach) { if (test_bit(MLX5_INTERFACE_ATTACHED, &dev_ctx->state)) goto out; - intf->attach(dev, dev_ctx->context); + if (intf->attach(dev, dev_ctx->context)) + goto out; + set_bit(MLX5_INTERFACE_ATTACHED, &dev_ctx->state); } else { if (test_bit(MLX5_INTERFACE_ADDED, &dev_ctx->state)) goto out; dev_ctx->context = intf->add(dev); + if (!dev_ctx->context) + goto out; + set_bit(MLX5_INTERFACE_ADDED, &dev_ctx->state); } @@ -383,16 +388,17 @@ void mlx5_remove_dev_by_protocol(struct mlx5_core_dev *dev, int protocol) } } -static u16 mlx5_gen_pci_id(struct mlx5_core_dev *dev) +static u32 mlx5_gen_pci_id(struct mlx5_core_dev *dev) { - return (u16)((dev->pdev->bus->number << 8) | + return (u32)((pci_domain_nr(dev->pdev->bus) << 16) | + (dev->pdev->bus->number << 8) | PCI_SLOT(dev->pdev->devfn)); } /* Must be called with intf_mutex held */ struct mlx5_core_dev *mlx5_get_next_phys_dev(struct mlx5_core_dev *dev) { - u16 pci_id = mlx5_gen_pci_id(dev); + u32 pci_id = mlx5_gen_pci_id(dev); struct mlx5_core_dev *res = NULL; struct mlx5_core_dev *tmp_dev; struct mlx5_priv *priv; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index f697084937c381113632317f263d0af6abef3eee..de72b66df3e587d88aec9353c344afd66a8d08ee 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1525,17 +1525,15 @@ static void esw_disable_vport(struct mlx5_eswitch *esw, int vport_num) } /* Public E-Switch API */ -#define ESW_ALLOWED(esw) ((esw) && MLX5_VPORT_MANAGER((esw)->dev)) +#define ESW_ALLOWED(esw) ((esw) && MLX5_ESWITCH_MANAGER((esw)->dev)) + int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, int mode) { int err; int i, enabled_events; - if (!ESW_ALLOWED(esw)) - return 0; - - if (!MLX5_ESWITCH_MANAGER(esw->dev) || + if (!ESW_ALLOWED(esw) || !MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, ft_support)) { esw_warn(esw->dev, "E-Switch FDB is not supported, aborting ...\n"); return -EOPNOTSUPP; @@ -1728,7 +1726,7 @@ int mlx5_eswitch_set_vport_mac(struct mlx5_eswitch *esw, u64 node_guid; int err = 0; - if (!ESW_ALLOWED(esw)) + if (!MLX5_CAP_GEN(esw->dev, vport_group_manager)) return -EPERM; if (!LEGAL_VPORT(esw, vport) || is_multicast_ether_addr(mac)) return -EINVAL; @@ -1805,7 +1803,7 @@ int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw, { struct mlx5_vport *evport; - if (!ESW_ALLOWED(esw)) + if (!MLX5_CAP_GEN(esw->dev, vport_group_manager)) return -EPERM; if (!LEGAL_VPORT(esw, vport)) return -EINVAL; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index c699055c0ffdecde6ddaac99a10b2f6dbe1af4ce..4b52b722135d98ac20e04ad76056e3382f9d9f65 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -557,6 +557,7 @@ static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw, int nvports) if (err) goto miss_rule_err; + kvfree(flow_group_in); return 0; miss_rule_err: diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c index db86e1506c8b67fa8849940c4adc958fb783ac92..61f284966a8c99e506f3c0d0f76acafa199a05ab 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/health.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c @@ -333,9 +333,17 @@ void mlx5_start_health_poll(struct mlx5_core_dev *dev) add_timer(&health->timer); } -void mlx5_stop_health_poll(struct mlx5_core_dev *dev) +void mlx5_stop_health_poll(struct mlx5_core_dev *dev, bool disable_health) { struct mlx5_core_health *health = &dev->priv.health; + unsigned long flags; + + if (disable_health) { + spin_lock_irqsave(&health->wq_lock, flags); + set_bit(MLX5_DROP_NEW_HEALTH_WORK, &health->flags); + set_bit(MLX5_DROP_NEW_RECOVERY_WORK, &health->flags); + spin_unlock_irqrestore(&health->wq_lock, flags); + } del_timer_sync(&health->timer); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 4ddd632d10f9958c34238329f14faed02a021243..e99f1382a4f0ca334421f74da18659010923d707 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -857,8 +857,10 @@ static int mlx5_pci_init(struct mlx5_core_dev *dev, struct mlx5_priv *priv) priv->numa_node = dev_to_node(&dev->pdev->dev); priv->dbg_root = debugfs_create_dir(dev_name(&pdev->dev), mlx5_debugfs_root); - if (!priv->dbg_root) + if (!priv->dbg_root) { + dev_err(&pdev->dev, "Cannot create debugfs dir, aborting\n"); return -ENOMEM; + } err = mlx5_pci_enable_device(dev); if (err) { @@ -907,7 +909,7 @@ static void mlx5_pci_close(struct mlx5_core_dev *dev, struct mlx5_priv *priv) pci_clear_master(dev->pdev); release_bar(dev->pdev); mlx5_pci_disable_device(dev); - debugfs_remove(priv->dbg_root); + debugfs_remove_recursive(priv->dbg_root); } static int mlx5_init_once(struct mlx5_core_dev *dev, struct mlx5_priv *priv) @@ -1227,7 +1229,7 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv, mlx5_cleanup_once(dev); err_stop_poll: - mlx5_stop_health_poll(dev); + mlx5_stop_health_poll(dev, boot); if (mlx5_cmd_teardown_hca(dev)) { dev_err(&dev->pdev->dev, "tear_down_hca failed, skip cleanup\n"); goto out_err; @@ -1286,7 +1288,7 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv, mlx5_free_irq_vectors(dev); if (cleanup) mlx5_cleanup_once(dev); - mlx5_stop_health_poll(dev); + mlx5_stop_health_poll(dev, cleanup); err = mlx5_cmd_teardown_hca(dev); if (err) { dev_err(&dev->pdev->dev, "tear_down_hca failed, skip cleanup\n"); @@ -1548,7 +1550,7 @@ static int mlx5_try_fast_unload(struct mlx5_core_dev *dev) * with the HCA, so the health polll is no longer needed. */ mlx5_drain_health_wq(dev); - mlx5_stop_health_poll(dev); + mlx5_stop_health_poll(dev, false); ret = mlx5_cmd_force_teardown_hca(dev); if (ret) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c index 71153c0f16054a2e987972b067c0070a54863e88..aa9a88e84e3bf5c1056ee178b87a659020d5e041 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c @@ -549,8 +549,6 @@ int mlx5_modify_nic_vport_node_guid(struct mlx5_core_dev *mdev, return -EINVAL; if (!MLX5_CAP_GEN(mdev, vport_group_manager)) return -EACCES; - if (!MLX5_CAP_ESW(mdev, nic_vport_node_guid_modify)) - return -EOPNOTSUPP; in = kvzalloc(inlen, GFP_KERNEL); if (!in) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 8c4ce0a0cc825e93999f5130ede9f136052da35c..06eeea6b2f93111be564f22adfe1e0403eab9249 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -395,6 +395,8 @@ int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event, void mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif); +void mlxsw_sp_rif_destroy_by_dev(struct mlxsw_sp *mlxsw_sp, + struct net_device *dev); /* spectrum_kvdl.c */ int mlxsw_sp_kvdl_alloc(struct mlxsw_sp *mlxsw_sp, unsigned int entry_count, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 516e6324460676ce84cf09dc00b74309695e00c5..3ed4fb346f2357fce463bc812f5c22dc21015b39 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -5131,6 +5131,17 @@ void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif) mlxsw_sp_vr_put(vr); } +void mlxsw_sp_rif_destroy_by_dev(struct mlxsw_sp *mlxsw_sp, + struct net_device *dev) +{ + struct mlxsw_sp_rif *rif; + + rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev); + if (!rif) + return; + mlxsw_sp_rif_destroy(rif); +} + static void mlxsw_sp_rif_subport_params_init(struct mlxsw_sp_rif_params *params, struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 7924f241e3ad068ed68ef295e967384ac559a08d..32c25772f75586dbb4884b6afc2c84d08931702d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -140,6 +140,24 @@ bool mlxsw_sp_bridge_device_is_offloaded(const struct mlxsw_sp *mlxsw_sp, return !!mlxsw_sp_bridge_device_find(mlxsw_sp->bridge, br_dev); } +static int mlxsw_sp_bridge_device_upper_rif_destroy(struct net_device *dev, + void *data) +{ + struct mlxsw_sp *mlxsw_sp = data; + + mlxsw_sp_rif_destroy_by_dev(mlxsw_sp, dev); + return 0; +} + +static void mlxsw_sp_bridge_device_rifs_destroy(struct mlxsw_sp *mlxsw_sp, + struct net_device *dev) +{ + mlxsw_sp_rif_destroy_by_dev(mlxsw_sp, dev); + netdev_walk_all_upper_dev_rcu(dev, + mlxsw_sp_bridge_device_upper_rif_destroy, + mlxsw_sp); +} + static struct mlxsw_sp_bridge_device * mlxsw_sp_bridge_device_create(struct mlxsw_sp_bridge *bridge, struct net_device *br_dev) @@ -176,6 +194,8 @@ static void mlxsw_sp_bridge_device_destroy(struct mlxsw_sp_bridge *bridge, struct mlxsw_sp_bridge_device *bridge_device) { + mlxsw_sp_bridge_device_rifs_destroy(bridge->mlxsw_sp, + bridge_device->dev); list_del(&bridge_device->list); if (bridge_device->vlan_enabled) bridge->vlan_enabled_exists = false; diff --git a/drivers/net/ethernet/netronome/nfp/flower/main.c b/drivers/net/ethernet/netronome/nfp/flower/main.c index 91fe0361710657ecbd6fba6dcc54b00894019480..72496060e3328e2be01b05be649f13e0f835b219 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/main.c +++ b/drivers/net/ethernet/netronome/nfp/flower/main.c @@ -79,7 +79,7 @@ nfp_flower_repr_get_type_and_port(struct nfp_app *app, u32 port_id, u8 *port) return NFP_REPR_TYPE_VF; } - return NFP_FLOWER_CMSG_PORT_TYPE_UNSPEC; + return __NFP_REPR_TYPE_MAX; } static struct net_device * @@ -90,6 +90,8 @@ nfp_flower_repr_get(struct nfp_app *app, u32 port_id) u8 port = 0; repr_type = nfp_flower_repr_get_type_and_port(app, port_id, &port); + if (repr_type > NFP_REPR_TYPE_MAX) + return NULL; reprs = rcu_dereference(app->reprs[repr_type]); if (!reprs) diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 8d53a593fb27435052d5bcbbecac6a3b86aec873..56751990bceefc9e9fa27a1d6cd82980c443fd1c 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -227,29 +227,16 @@ static void nfp_net_reconfig_post(struct nfp_net *nn, u32 update) spin_unlock_bh(&nn->reconfig_lock); } -/** - * nfp_net_reconfig() - Reconfigure the firmware - * @nn: NFP Net device to reconfigure - * @update: The value for the update field in the BAR config - * - * Write the update word to the BAR and ping the reconfig queue. The - * poll until the firmware has acknowledged the update by zeroing the - * update word. - * - * Return: Negative errno on error, 0 on success - */ -int nfp_net_reconfig(struct nfp_net *nn, u32 update) +static void nfp_net_reconfig_sync_enter(struct nfp_net *nn) { bool cancelled_timer = false; u32 pre_posted_requests; - int ret; spin_lock_bh(&nn->reconfig_lock); nn->reconfig_sync_present = true; if (nn->reconfig_timer_active) { - del_timer(&nn->reconfig_timer); nn->reconfig_timer_active = false; cancelled_timer = true; } @@ -258,14 +245,43 @@ int nfp_net_reconfig(struct nfp_net *nn, u32 update) spin_unlock_bh(&nn->reconfig_lock); - if (cancelled_timer) + if (cancelled_timer) { + del_timer_sync(&nn->reconfig_timer); nfp_net_reconfig_wait(nn, nn->reconfig_timer.expires); + } /* Run the posted reconfigs which were issued before we started */ if (pre_posted_requests) { nfp_net_reconfig_start(nn, pre_posted_requests); nfp_net_reconfig_wait(nn, jiffies + HZ * NFP_NET_POLL_TIMEOUT); } +} + +static void nfp_net_reconfig_wait_posted(struct nfp_net *nn) +{ + nfp_net_reconfig_sync_enter(nn); + + spin_lock_bh(&nn->reconfig_lock); + nn->reconfig_sync_present = false; + spin_unlock_bh(&nn->reconfig_lock); +} + +/** + * nfp_net_reconfig() - Reconfigure the firmware + * @nn: NFP Net device to reconfigure + * @update: The value for the update field in the BAR config + * + * Write the update word to the BAR and ping the reconfig queue. The + * poll until the firmware has acknowledged the update by zeroing the + * update word. + * + * Return: Negative errno on error, 0 on success + */ +int nfp_net_reconfig(struct nfp_net *nn, u32 update) +{ + int ret; + + nfp_net_reconfig_sync_enter(nn); nfp_net_reconfig_start(nn, update); ret = nfp_net_reconfig_wait(nn, jiffies + HZ * NFP_NET_POLL_TIMEOUT); @@ -1071,7 +1087,7 @@ static bool nfp_net_xdp_complete(struct nfp_net_tx_ring *tx_ring) * @dp: NFP Net data path struct * @tx_ring: TX ring structure * - * Assumes that the device is stopped + * Assumes that the device is stopped, must be idempotent. */ static void nfp_net_tx_ring_reset(struct nfp_net_dp *dp, struct nfp_net_tx_ring *tx_ring) @@ -1273,13 +1289,18 @@ static void nfp_net_rx_give_one(const struct nfp_net_dp *dp, * nfp_net_rx_ring_reset() - Reflect in SW state of freelist after disable * @rx_ring: RX ring structure * - * Warning: Do *not* call if ring buffers were never put on the FW freelist - * (i.e. device was not enabled)! + * Assumes that the device is stopped, must be idempotent. */ static void nfp_net_rx_ring_reset(struct nfp_net_rx_ring *rx_ring) { unsigned int wr_idx, last_idx; + /* wr_p == rd_p means ring was never fed FL bufs. RX rings are always + * kept at cnt - 1 FL bufs. + */ + if (rx_ring->wr_p == 0 && rx_ring->rd_p == 0) + return; + /* Move the empty entry to the end of the list */ wr_idx = D_IDX(rx_ring, rx_ring->wr_p); last_idx = rx_ring->cnt - 1; @@ -2489,6 +2510,8 @@ static void nfp_net_vec_clear_ring_data(struct nfp_net *nn, unsigned int idx) /** * nfp_net_clear_config_and_disable() - Clear control BAR and disable NFP * @nn: NFP Net device to reconfigure + * + * Warning: must be fully idempotent. */ static void nfp_net_clear_config_and_disable(struct nfp_net *nn) { @@ -3560,6 +3583,7 @@ struct nfp_net *nfp_net_alloc(struct pci_dev *pdev, bool needs_netdev, */ void nfp_net_free(struct nfp_net *nn) { + WARN_ON(timer_pending(&nn->reconfig_timer) || nn->reconfig_posted); if (nn->xdp_prog) bpf_prog_put(nn->xdp_prog); @@ -3829,4 +3853,5 @@ void nfp_net_clean(struct nfp_net *nn) return; unregister_netdev(nn->dp.netdev); + nfp_net_reconfig_wait_posted(nn); } diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c index cd34097b79f1be9d313d8f28b9701bb5bd6a3100..37a6d7822a3860647c416efeff47c7a7837a3a85 100644 --- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c +++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nffw.c @@ -232,7 +232,7 @@ struct nfp_nffw_info *nfp_nffw_info_open(struct nfp_cpp *cpp) err = nfp_cpp_read(cpp, nfp_resource_cpp_id(state->res), nfp_resource_address(state->res), fwinf, sizeof(*fwinf)); - if (err < sizeof(*fwinf)) + if (err < (int)sizeof(*fwinf)) goto err_release; if (!nffw_res_flg_init_get(fwinf)) diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c index b306961b02fdf40aef89db7d5ed1e535a98a65a1..d62dccb85539404f8173e5713d805a096859b09a 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c @@ -255,9 +255,8 @@ qed_dcbx_get_app_protocol_type(struct qed_hwfn *p_hwfn, *type = DCBX_PROTOCOL_ROCE_V2; } else { *type = DCBX_MAX_PROTOCOL_TYPE; - DP_ERR(p_hwfn, - "No action required, App TLV id = 0x%x app_prio_bitmap = 0x%x\n", - id, app_prio_bitmap); + DP_ERR(p_hwfn, "No action required, App TLV entry = 0x%x\n", + app_prio_bitmap); return false; } @@ -1472,8 +1471,8 @@ static u8 qed_dcbnl_getcap(struct qed_dev *cdev, int capid, u8 *cap) *cap = 0x80; break; case DCB_CAP_ATTR_DCBX: - *cap = (DCB_CAP_DCBX_LLD_MANAGED | DCB_CAP_DCBX_VER_CEE | - DCB_CAP_DCBX_VER_IEEE | DCB_CAP_DCBX_STATIC); + *cap = (DCB_CAP_DCBX_VER_CEE | DCB_CAP_DCBX_VER_IEEE | + DCB_CAP_DCBX_STATIC); break; default: *cap = false; @@ -1541,8 +1540,6 @@ static u8 qed_dcbnl_getdcbx(struct qed_dev *cdev) if (!dcbx_info) return 0; - if (dcbx_info->operational.enabled) - mode |= DCB_CAP_DCBX_LLD_MANAGED; if (dcbx_info->operational.ieee) mode |= DCB_CAP_DCBX_VER_IEEE; if (dcbx_info->operational.cee) diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c index c5452b445c37c142de2eb3cc083ec1a2516a366d..83c1c4fa102b7bce5ce9822653f0f7688446a50f 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c @@ -663,7 +663,7 @@ qed_sp_update_mcast_bin(struct qed_hwfn *p_hwfn, p_ramrod->common.update_approx_mcast_flg = 1; for (i = 0; i < ETH_MULTICAST_MAC_BINS_IN_REGS; i++) { - u32 *p_bins = (u32 *)p_params->bins; + u32 *p_bins = p_params->bins; p_ramrod->approx_mcast.bins[i] = cpu_to_le32(p_bins[i]); } @@ -1474,8 +1474,8 @@ qed_sp_eth_filter_mcast(struct qed_hwfn *p_hwfn, enum spq_mode comp_mode, struct qed_spq_comp_cb *p_comp_data) { - unsigned long bins[ETH_MULTICAST_MAC_BINS_IN_REGS]; struct vport_update_ramrod_data *p_ramrod = NULL; + u32 bins[ETH_MULTICAST_MAC_BINS_IN_REGS]; struct qed_spq_entry *p_ent = NULL; struct qed_sp_init_data init_data; u8 abs_vport_id = 0; @@ -1511,26 +1511,25 @@ qed_sp_eth_filter_mcast(struct qed_hwfn *p_hwfn, /* explicitly clear out the entire vector */ memset(&p_ramrod->approx_mcast.bins, 0, sizeof(p_ramrod->approx_mcast.bins)); - memset(bins, 0, sizeof(unsigned long) * - ETH_MULTICAST_MAC_BINS_IN_REGS); + memset(bins, 0, sizeof(bins)); /* filter ADD op is explicit set op and it removes * any existing filters for the vport */ if (p_filter_cmd->opcode == QED_FILTER_ADD) { for (i = 0; i < p_filter_cmd->num_mc_addrs; i++) { - u32 bit; + u32 bit, nbits; bit = qed_mcast_bin_from_mac(p_filter_cmd->mac[i]); - __set_bit(bit, bins); + nbits = sizeof(u32) * BITS_PER_BYTE; + bins[bit / nbits] |= 1 << (bit % nbits); } /* Convert to correct endianity */ for (i = 0; i < ETH_MULTICAST_MAC_BINS_IN_REGS; i++) { struct vport_update_ramrod_mcast *p_ramrod_bins; - u32 *p_bins = (u32 *)bins; p_ramrod_bins = &p_ramrod->approx_mcast; - p_ramrod_bins->bins[i] = cpu_to_le32(p_bins[i]); + p_ramrod_bins->bins[i] = cpu_to_le32(bins[i]); } } diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.h b/drivers/net/ethernet/qlogic/qed/qed_l2.h index cc1f248551c9d4a13c5235ba00d83ebcd24b61b1..91d383f3a661ff5898d9268166fb33e8ebf64e05 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.h +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.h @@ -214,7 +214,7 @@ struct qed_sp_vport_update_params { u8 anti_spoofing_en; u8 update_accept_any_vlan_flg; u8 accept_any_vlan; - unsigned long bins[8]; + u32 bins[8]; struct qed_rss_params *rss_params; struct qed_filter_accept_flags accept_flags; struct qed_sge_tpa_params *sge_tpa_params; diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c index c06ad4f0758eb755ad9d82ffccecc3def154fc6b..5f52f14761a30472c8a483474256fdb70d6c3861 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c @@ -201,8 +201,9 @@ void qed_ll2b_complete_rx_packet(void *cxt, struct qed_ll2_comp_rx_data *data) skb = build_skb(buffer->data, 0); if (!skb) { - rc = -ENOMEM; - goto out_post; + DP_INFO(cdev, "Failed to build SKB\n"); + kfree(buffer->data); + goto out_post1; } data->u.placement_offset += NET_SKB_PAD; @@ -224,8 +225,14 @@ void qed_ll2b_complete_rx_packet(void *cxt, struct qed_ll2_comp_rx_data *data) cdev->ll2->cbs->rx_cb(cdev->ll2->cb_cookie, skb, data->opaque_data_0, data->opaque_data_1); + } else { + DP_VERBOSE(p_hwfn, (NETIF_MSG_RX_STATUS | NETIF_MSG_PKTDATA | + QED_MSG_LL2 | QED_MSG_STORAGE), + "Dropping the packet\n"); + kfree(buffer->data); } +out_post1: /* Update Buffer information and update FW producer */ buffer->data = new_data; buffer->phys_addr = new_phys_addr; diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index 2c958921dfb36f876594b6b0f7f22d67628731fb..954f7ce4cf2850a4130742bbd1e67e07ae1deea9 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -565,8 +565,16 @@ static irqreturn_t qed_single_int(int irq, void *dev_instance) /* Fastpath interrupts */ for (j = 0; j < 64; j++) { if ((0x2ULL << j) & status) { - hwfn->simd_proto_handler[j].func( - hwfn->simd_proto_handler[j].token); + struct qed_simd_fp_handler *p_handler = + &hwfn->simd_proto_handler[j]; + + if (p_handler->func) + p_handler->func(p_handler->token); + else + DP_NOTICE(hwfn, + "Not calling fastpath handler as it is NULL [handler #%d, status 0x%llx]\n", + j, status); + status &= ~(0x2ULL << j); rc = IRQ_HANDLED; } diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c index 376485d99357dc0ca18dde626300da1327e35721..7938abe9a30106450245ff94f8a28a155dcac54f 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c @@ -47,7 +47,7 @@ #include "qed_reg_addr.h" #include "qed_sriov.h" -#define CHIP_MCP_RESP_ITER_US 10 +#define QED_MCP_RESP_ITER_US 10 #define QED_DRV_MB_MAX_RETRIES (500 * 1000) /* Account for 5 sec */ #define QED_MCP_RESET_RETRIES (50 * 1000) /* Account for 500 msec */ @@ -182,18 +182,57 @@ int qed_mcp_free(struct qed_hwfn *p_hwfn) return 0; } +/* Maximum of 1 sec to wait for the SHMEM ready indication */ +#define QED_MCP_SHMEM_RDY_MAX_RETRIES 20 +#define QED_MCP_SHMEM_RDY_ITER_MS 50 + static int qed_load_mcp_offsets(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { struct qed_mcp_info *p_info = p_hwfn->mcp_info; + u8 cnt = QED_MCP_SHMEM_RDY_MAX_RETRIES; + u8 msec = QED_MCP_SHMEM_RDY_ITER_MS; u32 drv_mb_offsize, mfw_mb_offsize; u32 mcp_pf_id = MCP_PF_ID(p_hwfn); p_info->public_base = qed_rd(p_hwfn, p_ptt, MISC_REG_SHARED_MEM_ADDR); - if (!p_info->public_base) - return 0; + if (!p_info->public_base) { + DP_NOTICE(p_hwfn, + "The address of the MCP scratch-pad is not configured\n"); + return -EINVAL; + } p_info->public_base |= GRCBASE_MCP; + /* Get the MFW MB address and number of supported messages */ + mfw_mb_offsize = qed_rd(p_hwfn, p_ptt, + SECTION_OFFSIZE_ADDR(p_info->public_base, + PUBLIC_MFW_MB)); + p_info->mfw_mb_addr = SECTION_ADDR(mfw_mb_offsize, mcp_pf_id); + p_info->mfw_mb_length = (u16)qed_rd(p_hwfn, p_ptt, + p_info->mfw_mb_addr + + offsetof(struct public_mfw_mb, + sup_msgs)); + + /* The driver can notify that there was an MCP reset, and might read the + * SHMEM values before the MFW has completed initializing them. + * To avoid this, the "sup_msgs" field in the MFW mailbox is used as a + * data ready indication. + */ + while (!p_info->mfw_mb_length && --cnt) { + msleep(msec); + p_info->mfw_mb_length = + (u16)qed_rd(p_hwfn, p_ptt, + p_info->mfw_mb_addr + + offsetof(struct public_mfw_mb, sup_msgs)); + } + + if (!cnt) { + DP_NOTICE(p_hwfn, + "Failed to get the SHMEM ready notification after %d msec\n", + QED_MCP_SHMEM_RDY_MAX_RETRIES * msec); + return -EBUSY; + } + /* Calculate the driver and MFW mailbox address */ drv_mb_offsize = qed_rd(p_hwfn, p_ptt, SECTION_OFFSIZE_ADDR(p_info->public_base, @@ -203,13 +242,6 @@ static int qed_load_mcp_offsets(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) "drv_mb_offsiz = 0x%x, drv_mb_addr = 0x%x mcp_pf_id = 0x%x\n", drv_mb_offsize, p_info->drv_mb_addr, mcp_pf_id); - /* Set the MFW MB address */ - mfw_mb_offsize = qed_rd(p_hwfn, p_ptt, - SECTION_OFFSIZE_ADDR(p_info->public_base, - PUBLIC_MFW_MB)); - p_info->mfw_mb_addr = SECTION_ADDR(mfw_mb_offsize, mcp_pf_id); - p_info->mfw_mb_length = (u16)qed_rd(p_hwfn, p_ptt, p_info->mfw_mb_addr); - /* Get the current driver mailbox sequence before sending * the first command */ @@ -284,9 +316,15 @@ static void qed_mcp_reread_offsets(struct qed_hwfn *p_hwfn, int qed_mcp_reset(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { - u32 org_mcp_reset_seq, seq, delay = CHIP_MCP_RESP_ITER_US, cnt = 0; + u32 org_mcp_reset_seq, seq, delay = QED_MCP_RESP_ITER_US, cnt = 0; int rc = 0; + if (p_hwfn->mcp_info->b_block_cmd) { + DP_NOTICE(p_hwfn, + "The MFW is not responsive. Avoid sending MCP_RESET mailbox command.\n"); + return -EBUSY; + } + /* Ensure that only a single thread is accessing the mailbox */ spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); @@ -412,14 +450,41 @@ static void __qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, (p_mb_params->cmd | seq_num), p_mb_params->param); } +static void qed_mcp_cmd_set_blocking(struct qed_hwfn *p_hwfn, bool block_cmd) +{ + p_hwfn->mcp_info->b_block_cmd = block_cmd; + + DP_INFO(p_hwfn, "%s sending of mailbox commands to the MFW\n", + block_cmd ? "Block" : "Unblock"); +} + +static void qed_mcp_print_cpu_info(struct qed_hwfn *p_hwfn, + struct qed_ptt *p_ptt) +{ + u32 cpu_mode, cpu_state, cpu_pc_0, cpu_pc_1, cpu_pc_2; + u32 delay = QED_MCP_RESP_ITER_US; + + cpu_mode = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE); + cpu_state = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_STATE); + cpu_pc_0 = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_PROGRAM_COUNTER); + udelay(delay); + cpu_pc_1 = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_PROGRAM_COUNTER); + udelay(delay); + cpu_pc_2 = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_PROGRAM_COUNTER); + + DP_NOTICE(p_hwfn, + "MCP CPU info: mode 0x%08x, state 0x%08x, pc {0x%08x, 0x%08x, 0x%08x}\n", + cpu_mode, cpu_state, cpu_pc_0, cpu_pc_1, cpu_pc_2); +} + static int _qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, struct qed_mcp_mb_params *p_mb_params, - u32 max_retries, u32 delay) + u32 max_retries, u32 usecs) { + u32 cnt = 0, msecs = DIV_ROUND_UP(usecs, 1000); struct qed_mcp_cmd_elem *p_cmd_elem; - u32 cnt = 0; u16 seq_num; int rc = 0; @@ -442,7 +507,11 @@ _qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, goto err; spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); - udelay(delay); + + if (QED_MB_FLAGS_IS_SET(p_mb_params, CAN_SLEEP)) + msleep(msecs); + else + udelay(usecs); } while (++cnt < max_retries); if (cnt >= max_retries) { @@ -471,7 +540,11 @@ _qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, * The spinlock stays locked until the list element is removed. */ - udelay(delay); + if (QED_MB_FLAGS_IS_SET(p_mb_params, CAN_SLEEP)) + msleep(msecs); + else + udelay(usecs); + spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); if (p_cmd_elem->b_is_completed) @@ -490,11 +563,15 @@ _qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, DP_NOTICE(p_hwfn, "The MFW failed to respond to command 0x%08x [param 0x%08x].\n", p_mb_params->cmd, p_mb_params->param); + qed_mcp_print_cpu_info(p_hwfn, p_ptt); spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); qed_mcp_cmd_del_elem(p_hwfn, p_cmd_elem); spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); + if (!QED_MB_FLAGS_IS_SET(p_mb_params, AVOID_BLOCK)) + qed_mcp_cmd_set_blocking(p_hwfn, true); + return -EAGAIN; } @@ -506,7 +583,7 @@ _qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, "MFW mailbox: response 0x%08x param 0x%08x [after %d.%03d ms]\n", p_mb_params->mcp_resp, p_mb_params->mcp_param, - (cnt * delay) / 1000, (cnt * delay) % 1000); + (cnt * usecs) / 1000, (cnt * usecs) % 1000); /* Clear the sequence number from the MFW response */ p_mb_params->mcp_resp &= FW_MSG_CODE_MASK; @@ -524,7 +601,7 @@ static int qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, { size_t union_data_size = sizeof(union drv_union_data); u32 max_retries = QED_DRV_MB_MAX_RETRIES; - u32 delay = CHIP_MCP_RESP_ITER_US; + u32 usecs = QED_MCP_RESP_ITER_US; /* MCP not initialized */ if (!qed_mcp_is_init(p_hwfn)) { @@ -532,6 +609,13 @@ static int qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, return -EBUSY; } + if (p_hwfn->mcp_info->b_block_cmd) { + DP_NOTICE(p_hwfn, + "The MFW is not responsive. Avoid sending mailbox command 0x%08x [param 0x%08x].\n", + p_mb_params->cmd, p_mb_params->param); + return -EBUSY; + } + if (p_mb_params->data_src_size > union_data_size || p_mb_params->data_dst_size > union_data_size) { DP_ERR(p_hwfn, @@ -541,8 +625,13 @@ static int qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, return -EINVAL; } + if (QED_MB_FLAGS_IS_SET(p_mb_params, CAN_SLEEP)) { + max_retries = DIV_ROUND_UP(max_retries, 1000); + usecs *= 1000; + } + return _qed_mcp_cmd_and_union(p_hwfn, p_ptt, p_mb_params, max_retries, - delay); + usecs); } int qed_mcp_cmd(struct qed_hwfn *p_hwfn, @@ -731,6 +820,7 @@ __qed_mcp_load_req(struct qed_hwfn *p_hwfn, mb_params.data_src_size = sizeof(load_req); mb_params.p_data_dst = &load_rsp; mb_params.data_dst_size = sizeof(load_rsp); + mb_params.flags = QED_MB_FLAG_CAN_SLEEP | QED_MB_FLAG_AVOID_BLOCK; DP_VERBOSE(p_hwfn, QED_MSG_SP, "Load Request: param 0x%08x [init_hw %d, drv_type %d, hsi_ver %d, pda 0x%04x]\n", @@ -952,7 +1042,8 @@ int qed_mcp_load_req(struct qed_hwfn *p_hwfn, int qed_mcp_unload_req(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { - u32 wol_param, mcp_resp, mcp_param; + struct qed_mcp_mb_params mb_params; + u32 wol_param; switch (p_hwfn->cdev->wol_config) { case QED_OV_WOL_DISABLED: @@ -970,8 +1061,12 @@ int qed_mcp_unload_req(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) wol_param = DRV_MB_PARAM_UNLOAD_WOL_MCP; } - return qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_UNLOAD_REQ, wol_param, - &mcp_resp, &mcp_param); + memset(&mb_params, 0, sizeof(mb_params)); + mb_params.cmd = DRV_MSG_CODE_UNLOAD_REQ; + mb_params.param = wol_param; + mb_params.flags = QED_MB_FLAG_CAN_SLEEP | QED_MB_FLAG_AVOID_BLOCK; + + return qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); } int qed_mcp_unload_done(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) @@ -1182,6 +1277,7 @@ static void qed_mcp_handle_link_change(struct qed_hwfn *p_hwfn, break; default: p_link->speed = 0; + p_link->link_up = 0; } if (p_link->link_up && p_link->speed) @@ -1279,9 +1375,15 @@ int qed_mcp_set_link(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool b_up) phy_cfg.pause |= (params->pause.forced_tx) ? ETH_PAUSE_TX : 0; phy_cfg.adv_speed = params->speed.advertised_speeds; phy_cfg.loopback_mode = params->loopback_mode; - if (p_hwfn->mcp_info->capabilities & FW_MB_PARAM_FEATURE_SUPPORT_EEE) { - if (params->eee.enable) - phy_cfg.eee_cfg |= EEE_CFG_EEE_ENABLED; + + /* There are MFWs that share this capability regardless of whether + * this is feasible or not. And given that at the very least adv_caps + * would be set internally by qed, we want to make sure LFA would + * still work. + */ + if ((p_hwfn->mcp_info->capabilities & + FW_MB_PARAM_FEATURE_SUPPORT_EEE) && params->eee.enable) { + phy_cfg.eee_cfg |= EEE_CFG_EEE_ENABLED; if (params->eee.tx_lpi_enable) phy_cfg.eee_cfg |= EEE_CFG_TX_LPI; if (params->eee.adv_caps & QED_EEE_1G_ADV) @@ -1959,31 +2061,65 @@ qed_mcp_send_drv_version(struct qed_hwfn *p_hwfn, return rc; } +/* A maximal 100 msec waiting time for the MCP to halt */ +#define QED_MCP_HALT_SLEEP_MS 10 +#define QED_MCP_HALT_MAX_RETRIES 10 + int qed_mcp_halt(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { - u32 resp = 0, param = 0; + u32 resp = 0, param = 0, cpu_state, cnt = 0; int rc; rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_MCP_HALT, 0, &resp, ¶m); - if (rc) + if (rc) { DP_ERR(p_hwfn, "MCP response failure, aborting\n"); + return rc; + } - return rc; + do { + msleep(QED_MCP_HALT_SLEEP_MS); + cpu_state = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_STATE); + if (cpu_state & MCP_REG_CPU_STATE_SOFT_HALTED) + break; + } while (++cnt < QED_MCP_HALT_MAX_RETRIES); + + if (cnt == QED_MCP_HALT_MAX_RETRIES) { + DP_NOTICE(p_hwfn, + "Failed to halt the MCP [CPU_MODE = 0x%08x, CPU_STATE = 0x%08x]\n", + qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE), cpu_state); + return -EBUSY; + } + + qed_mcp_cmd_set_blocking(p_hwfn, true); + + return 0; } +#define QED_MCP_RESUME_SLEEP_MS 10 + int qed_mcp_resume(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { - u32 value, cpu_mode; + u32 cpu_mode, cpu_state; qed_wr(p_hwfn, p_ptt, MCP_REG_CPU_STATE, 0xffffffff); - value = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE); - value &= ~MCP_REG_CPU_MODE_SOFT_HALT; - qed_wr(p_hwfn, p_ptt, MCP_REG_CPU_MODE, value); cpu_mode = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE); + cpu_mode &= ~MCP_REG_CPU_MODE_SOFT_HALT; + qed_wr(p_hwfn, p_ptt, MCP_REG_CPU_MODE, cpu_mode); + msleep(QED_MCP_RESUME_SLEEP_MS); + cpu_state = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_STATE); - return (cpu_mode & MCP_REG_CPU_MODE_SOFT_HALT) ? -EAGAIN : 0; + if (cpu_state & MCP_REG_CPU_STATE_SOFT_HALTED) { + DP_NOTICE(p_hwfn, + "Failed to resume the MCP [CPU_MODE = 0x%08x, CPU_STATE = 0x%08x]\n", + cpu_mode, cpu_state); + return -EBUSY; + } + + qed_mcp_cmd_set_blocking(p_hwfn, false); + + return 0; } int qed_mcp_ov_update_current_config(struct qed_hwfn *p_hwfn, diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.h b/drivers/net/ethernet/qlogic/qed/qed_mcp.h index c7ec2395d1cebd795c9cd33de937da4de6099513..f1fe5e3427ea54f55831563e2a89e4aeea7ad2aa 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.h @@ -540,11 +540,14 @@ struct qed_mcp_info { */ spinlock_t cmd_lock; + /* Flag to indicate whether sending a MFW mailbox command is blocked */ + bool b_block_cmd; + /* Spinlock used for syncing SW link-changes and link-changes * originating from attention context. */ spinlock_t link_lock; - bool block_mb_sending; + u32 public_base; u32 drv_mb_addr; u32 mfw_mb_addr; @@ -565,14 +568,20 @@ struct qed_mcp_info { }; struct qed_mcp_mb_params { - u32 cmd; - u32 param; - void *p_data_src; - u8 data_src_size; - void *p_data_dst; - u8 data_dst_size; - u32 mcp_resp; - u32 mcp_param; + u32 cmd; + u32 param; + void *p_data_src; + void *p_data_dst; + u8 data_src_size; + u8 data_dst_size; + u32 mcp_resp; + u32 mcp_param; + u32 flags; +#define QED_MB_FLAG_CAN_SLEEP (0x1 << 0) +#define QED_MB_FLAG_AVOID_BLOCK (0x1 << 1) +#define QED_MB_FLAGS_IS_SET(params, flag) \ + ({ typeof(params) __params = (params); \ + (__params && (__params->flags & QED_MB_FLAG_ ## flag)); }) }; /** diff --git a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h index 0cdb4337b3a057befc98b3c69c0d65085d81b918..d1201bb2d4bb7d6ef28ca19d74f2b32fd2271a42 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h +++ b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h @@ -554,8 +554,10 @@ 0 #define MCP_REG_CPU_STATE \ 0xe05004UL +#define MCP_REG_CPU_STATE_SOFT_HALTED (0x1UL << 10) #define MCP_REG_CPU_EVENT_MASK \ 0xe05008UL +#define MCP_REG_CPU_PROGRAM_COUNTER 0xe0501cUL #define PGLUE_B_REG_PF_BAR0_SIZE \ 0x2aae60UL #define PGLUE_B_REG_PF_BAR1_SIZE \ diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c index d08fe350ab6cd3f925ce2de8768c893b82796c93..c6411158afd7b4f837c49311515ff4d6c29325fc 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c @@ -2826,7 +2826,7 @@ qed_iov_vp_update_mcast_bin_param(struct qed_hwfn *p_hwfn, p_data->update_approx_mcast_flg = 1; memcpy(p_data->bins, p_mcast_tlv->bins, - sizeof(unsigned long) * ETH_MULTICAST_MAC_BINS_IN_REGS); + sizeof(u32) * ETH_MULTICAST_MAC_BINS_IN_REGS); *tlvs_mask |= 1 << QED_IOV_VP_UPDATE_MCAST; } diff --git a/drivers/net/ethernet/qlogic/qed/qed_vf.c b/drivers/net/ethernet/qlogic/qed/qed_vf.c index 91b5e9f02a622cdfe4f1cff142d47c7a1b0b61ef..6eb85db69f9a9ada7c128706d60b434cd097d569 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_vf.c +++ b/drivers/net/ethernet/qlogic/qed/qed_vf.c @@ -1126,7 +1126,7 @@ int qed_vf_pf_vport_update(struct qed_hwfn *p_hwfn, resp_size += sizeof(struct pfvf_def_resp_tlv); memcpy(p_mcast_tlv->bins, p_params->bins, - sizeof(unsigned long) * ETH_MULTICAST_MAC_BINS_IN_REGS); + sizeof(u32) * ETH_MULTICAST_MAC_BINS_IN_REGS); } update_rx = p_params->accept_flags.update_rx_mode_config; @@ -1272,7 +1272,7 @@ void qed_vf_pf_filter_mcast(struct qed_hwfn *p_hwfn, u32 bit; bit = qed_mcast_bin_from_mac(p_filter_cmd->mac[i]); - __set_bit(bit, sp_params.bins); + sp_params.bins[bit / 32] |= 1 << (bit % 32); } } diff --git a/drivers/net/ethernet/qlogic/qed/qed_vf.h b/drivers/net/ethernet/qlogic/qed/qed_vf.h index 97d44dfb38ca2a3f9e9ca6e0585afcbe00378ca7..1e93c712fa346279cc2ec2d6038115ee91607c67 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_vf.h +++ b/drivers/net/ethernet/qlogic/qed/qed_vf.h @@ -392,7 +392,12 @@ struct vfpf_vport_update_mcast_bin_tlv { struct channel_tlv tl; u8 padding[4]; - u64 bins[8]; + /* There are only 256 approx bins, and in HSI they're divided into + * 32-bit values. As old VFs used to set-bit to the values on its side, + * the upper half of the array is never expected to contain any data. + */ + u64 bins[4]; + u64 obsolete_bins[4]; }; struct vfpf_vport_update_accept_param_tlv { diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c index 287d89dd086ff76981df302b847d882d887408c6..9c94240bb05ad7e88e97a0351ff6f57cb6b67882 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c @@ -1128,6 +1128,8 @@ static ssize_t qlcnic_83xx_sysfs_flash_write_handler(struct file *filp, struct qlcnic_adapter *adapter = dev_get_drvdata(dev); ret = kstrtoul(buf, 16, &data); + if (ret) + return ret; switch (data) { case QLC_83XX_FLASH_SECTOR_ERASE_CMD: diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c index 9feec70094435e19ee039f18ea430291d9f7d1a0..0e3b2890b92589771e11ff32660bde3c07ab6f20 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c +++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c @@ -2386,26 +2386,20 @@ static int qlge_update_hw_vlan_features(struct net_device *ndev, return status; } -static netdev_features_t qlge_fix_features(struct net_device *ndev, - netdev_features_t features) -{ - int err; - - /* Update the behavior of vlan accel in the adapter */ - err = qlge_update_hw_vlan_features(ndev, features); - if (err) - return err; - - return features; -} - static int qlge_set_features(struct net_device *ndev, netdev_features_t features) { netdev_features_t changed = ndev->features ^ features; + int err; + + if (changed & NETIF_F_HW_VLAN_CTAG_RX) { + /* Update the behavior of vlan accel in the adapter */ + err = qlge_update_hw_vlan_features(ndev, features); + if (err) + return err; - if (changed & NETIF_F_HW_VLAN_CTAG_RX) qlge_vlan_mode(ndev, features); + } return 0; } @@ -4719,7 +4713,6 @@ static const struct net_device_ops qlge_netdev_ops = { .ndo_set_mac_address = qlge_set_mac_address, .ndo_validate_addr = eth_validate_addr, .ndo_tx_timeout = qlge_tx_timeout, - .ndo_fix_features = qlge_fix_features, .ndo_set_features = qlge_set_features, .ndo_vlan_rx_add_vid = qlge_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = qlge_vlan_rx_kill_vid, diff --git a/drivers/net/ethernet/qualcomm/qca_7k.c b/drivers/net/ethernet/qualcomm/qca_7k.c index ffe7a16bdfc840d859292f6939938b75fba15a41..6c8543fb90c0a3ac780edd36aa701b01e7c9d94a 100644 --- a/drivers/net/ethernet/qualcomm/qca_7k.c +++ b/drivers/net/ethernet/qualcomm/qca_7k.c @@ -45,34 +45,33 @@ qcaspi_read_register(struct qcaspi *qca, u16 reg, u16 *result) { __be16 rx_data; __be16 tx_data; - struct spi_transfer *transfer; - struct spi_message *msg; + struct spi_transfer transfer[2]; + struct spi_message msg; int ret; + memset(transfer, 0, sizeof(transfer)); + + spi_message_init(&msg); + tx_data = cpu_to_be16(QCA7K_SPI_READ | QCA7K_SPI_INTERNAL | reg); + *result = 0; + + transfer[0].tx_buf = &tx_data; + transfer[0].len = QCASPI_CMD_LEN; + transfer[1].rx_buf = &rx_data; + transfer[1].len = QCASPI_CMD_LEN; + + spi_message_add_tail(&transfer[0], &msg); if (qca->legacy_mode) { - msg = &qca->spi_msg1; - transfer = &qca->spi_xfer1; - transfer->tx_buf = &tx_data; - transfer->rx_buf = NULL; - transfer->len = QCASPI_CMD_LEN; - spi_sync(qca->spi_dev, msg); - } else { - msg = &qca->spi_msg2; - transfer = &qca->spi_xfer2[0]; - transfer->tx_buf = &tx_data; - transfer->rx_buf = NULL; - transfer->len = QCASPI_CMD_LEN; - transfer = &qca->spi_xfer2[1]; + spi_sync(qca->spi_dev, &msg); + spi_message_init(&msg); } - transfer->tx_buf = NULL; - transfer->rx_buf = &rx_data; - transfer->len = QCASPI_CMD_LEN; - ret = spi_sync(qca->spi_dev, msg); + spi_message_add_tail(&transfer[1], &msg); + ret = spi_sync(qca->spi_dev, &msg); if (!ret) - ret = msg->status; + ret = msg.status; if (ret) qcaspi_spi_error(qca); @@ -86,35 +85,32 @@ int qcaspi_write_register(struct qcaspi *qca, u16 reg, u16 value) { __be16 tx_data[2]; - struct spi_transfer *transfer; - struct spi_message *msg; + struct spi_transfer transfer[2]; + struct spi_message msg; int ret; + memset(&transfer, 0, sizeof(transfer)); + + spi_message_init(&msg); + tx_data[0] = cpu_to_be16(QCA7K_SPI_WRITE | QCA7K_SPI_INTERNAL | reg); tx_data[1] = cpu_to_be16(value); + transfer[0].tx_buf = &tx_data[0]; + transfer[0].len = QCASPI_CMD_LEN; + transfer[1].tx_buf = &tx_data[1]; + transfer[1].len = QCASPI_CMD_LEN; + + spi_message_add_tail(&transfer[0], &msg); if (qca->legacy_mode) { - msg = &qca->spi_msg1; - transfer = &qca->spi_xfer1; - transfer->tx_buf = &tx_data[0]; - transfer->rx_buf = NULL; - transfer->len = QCASPI_CMD_LEN; - spi_sync(qca->spi_dev, msg); - } else { - msg = &qca->spi_msg2; - transfer = &qca->spi_xfer2[0]; - transfer->tx_buf = &tx_data[0]; - transfer->rx_buf = NULL; - transfer->len = QCASPI_CMD_LEN; - transfer = &qca->spi_xfer2[1]; + spi_sync(qca->spi_dev, &msg); + spi_message_init(&msg); } - transfer->tx_buf = &tx_data[1]; - transfer->rx_buf = NULL; - transfer->len = QCASPI_CMD_LEN; - ret = spi_sync(qca->spi_dev, msg); + spi_message_add_tail(&transfer[1], &msg); + ret = spi_sync(qca->spi_dev, &msg); if (!ret) - ret = msg->status; + ret = msg.status; if (ret) qcaspi_spi_error(qca); diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index 9c236298fe2125cf26afef756cfd5f3f7250098b..275fc6f154a71e52db57993d4e5e5c2d598abab9 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -99,22 +99,24 @@ static u32 qcaspi_write_burst(struct qcaspi *qca, u8 *src, u32 len) { __be16 cmd; - struct spi_message *msg = &qca->spi_msg2; - struct spi_transfer *transfer = &qca->spi_xfer2[0]; + struct spi_message msg; + struct spi_transfer transfer[2]; int ret; + memset(&transfer, 0, sizeof(transfer)); + spi_message_init(&msg); + cmd = cpu_to_be16(QCA7K_SPI_WRITE | QCA7K_SPI_EXTERNAL); - transfer->tx_buf = &cmd; - transfer->rx_buf = NULL; - transfer->len = QCASPI_CMD_LEN; - transfer = &qca->spi_xfer2[1]; - transfer->tx_buf = src; - transfer->rx_buf = NULL; - transfer->len = len; + transfer[0].tx_buf = &cmd; + transfer[0].len = QCASPI_CMD_LEN; + transfer[1].tx_buf = src; + transfer[1].len = len; - ret = spi_sync(qca->spi_dev, msg); + spi_message_add_tail(&transfer[0], &msg); + spi_message_add_tail(&transfer[1], &msg); + ret = spi_sync(qca->spi_dev, &msg); - if (ret || (msg->actual_length != QCASPI_CMD_LEN + len)) { + if (ret || (msg.actual_length != QCASPI_CMD_LEN + len)) { qcaspi_spi_error(qca); return 0; } @@ -125,17 +127,20 @@ qcaspi_write_burst(struct qcaspi *qca, u8 *src, u32 len) static u32 qcaspi_write_legacy(struct qcaspi *qca, u8 *src, u32 len) { - struct spi_message *msg = &qca->spi_msg1; - struct spi_transfer *transfer = &qca->spi_xfer1; + struct spi_message msg; + struct spi_transfer transfer; int ret; - transfer->tx_buf = src; - transfer->rx_buf = NULL; - transfer->len = len; + memset(&transfer, 0, sizeof(transfer)); + spi_message_init(&msg); + + transfer.tx_buf = src; + transfer.len = len; - ret = spi_sync(qca->spi_dev, msg); + spi_message_add_tail(&transfer, &msg); + ret = spi_sync(qca->spi_dev, &msg); - if (ret || (msg->actual_length != len)) { + if (ret || (msg.actual_length != len)) { qcaspi_spi_error(qca); return 0; } @@ -146,23 +151,25 @@ qcaspi_write_legacy(struct qcaspi *qca, u8 *src, u32 len) static u32 qcaspi_read_burst(struct qcaspi *qca, u8 *dst, u32 len) { - struct spi_message *msg = &qca->spi_msg2; + struct spi_message msg; __be16 cmd; - struct spi_transfer *transfer = &qca->spi_xfer2[0]; + struct spi_transfer transfer[2]; int ret; + memset(&transfer, 0, sizeof(transfer)); + spi_message_init(&msg); + cmd = cpu_to_be16(QCA7K_SPI_READ | QCA7K_SPI_EXTERNAL); - transfer->tx_buf = &cmd; - transfer->rx_buf = NULL; - transfer->len = QCASPI_CMD_LEN; - transfer = &qca->spi_xfer2[1]; - transfer->tx_buf = NULL; - transfer->rx_buf = dst; - transfer->len = len; + transfer[0].tx_buf = &cmd; + transfer[0].len = QCASPI_CMD_LEN; + transfer[1].rx_buf = dst; + transfer[1].len = len; - ret = spi_sync(qca->spi_dev, msg); + spi_message_add_tail(&transfer[0], &msg); + spi_message_add_tail(&transfer[1], &msg); + ret = spi_sync(qca->spi_dev, &msg); - if (ret || (msg->actual_length != QCASPI_CMD_LEN + len)) { + if (ret || (msg.actual_length != QCASPI_CMD_LEN + len)) { qcaspi_spi_error(qca); return 0; } @@ -173,17 +180,20 @@ qcaspi_read_burst(struct qcaspi *qca, u8 *dst, u32 len) static u32 qcaspi_read_legacy(struct qcaspi *qca, u8 *dst, u32 len) { - struct spi_message *msg = &qca->spi_msg1; - struct spi_transfer *transfer = &qca->spi_xfer1; + struct spi_message msg; + struct spi_transfer transfer; int ret; - transfer->tx_buf = NULL; - transfer->rx_buf = dst; - transfer->len = len; + memset(&transfer, 0, sizeof(transfer)); + spi_message_init(&msg); - ret = spi_sync(qca->spi_dev, msg); + transfer.rx_buf = dst; + transfer.len = len; - if (ret || (msg->actual_length != len)) { + spi_message_add_tail(&transfer, &msg); + ret = spi_sync(qca->spi_dev, &msg); + + if (ret || (msg.actual_length != len)) { qcaspi_spi_error(qca); return 0; } @@ -195,19 +205,23 @@ static int qcaspi_tx_cmd(struct qcaspi *qca, u16 cmd) { __be16 tx_data; - struct spi_message *msg = &qca->spi_msg1; - struct spi_transfer *transfer = &qca->spi_xfer1; + struct spi_message msg; + struct spi_transfer transfer; int ret; + memset(&transfer, 0, sizeof(transfer)); + + spi_message_init(&msg); + tx_data = cpu_to_be16(cmd); - transfer->len = sizeof(tx_data); - transfer->tx_buf = &tx_data; - transfer->rx_buf = NULL; + transfer.len = sizeof(cmd); + transfer.tx_buf = &tx_data; + spi_message_add_tail(&transfer, &msg); - ret = spi_sync(qca->spi_dev, msg); + ret = spi_sync(qca->spi_dev, &msg); if (!ret) - ret = msg->status; + ret = msg.status; if (ret) qcaspi_spi_error(qca); @@ -658,7 +672,7 @@ qcaspi_netdev_open(struct net_device *dev) return ret; } - netif_start_queue(qca->net_dev); + /* SPI thread takes care of TX queue */ return 0; } @@ -761,6 +775,9 @@ qcaspi_netdev_tx_timeout(struct net_device *dev) qca->net_dev->stats.tx_errors++; /* Trigger tx queue flush and QCA7000 reset */ qca->sync = QCASPI_SYNC_UNKNOWN; + + if (qca->spi_thread) + wake_up_process(qca->spi_thread); } static int @@ -833,16 +850,6 @@ qcaspi_netdev_setup(struct net_device *dev) qca = netdev_priv(dev); memset(qca, 0, sizeof(struct qcaspi)); - memset(&qca->spi_xfer1, 0, sizeof(struct spi_transfer)); - memset(&qca->spi_xfer2, 0, sizeof(struct spi_transfer) * 2); - - spi_message_init(&qca->spi_msg1); - spi_message_add_tail(&qca->spi_xfer1, &qca->spi_msg1); - - spi_message_init(&qca->spi_msg2); - spi_message_add_tail(&qca->spi_xfer2[0], &qca->spi_msg2); - spi_message_add_tail(&qca->spi_xfer2[1], &qca->spi_msg2); - memset(&qca->txr, 0, sizeof(qca->txr)); qca->txr.count = TX_RING_MAX_LEN; } @@ -879,22 +886,22 @@ qca_spi_probe(struct spi_device *spi) if ((qcaspi_clkspeed < QCASPI_CLK_SPEED_MIN) || (qcaspi_clkspeed > QCASPI_CLK_SPEED_MAX)) { - dev_info(&spi->dev, "Invalid clkspeed: %d\n", - qcaspi_clkspeed); + dev_err(&spi->dev, "Invalid clkspeed: %d\n", + qcaspi_clkspeed); return -EINVAL; } if ((qcaspi_burst_len < QCASPI_BURST_LEN_MIN) || (qcaspi_burst_len > QCASPI_BURST_LEN_MAX)) { - dev_info(&spi->dev, "Invalid burst len: %d\n", - qcaspi_burst_len); + dev_err(&spi->dev, "Invalid burst len: %d\n", + qcaspi_burst_len); return -EINVAL; } if ((qcaspi_pluggable < QCASPI_PLUGGABLE_MIN) || (qcaspi_pluggable > QCASPI_PLUGGABLE_MAX)) { - dev_info(&spi->dev, "Invalid pluggable: %d\n", - qcaspi_pluggable); + dev_err(&spi->dev, "Invalid pluggable: %d\n", + qcaspi_pluggable); return -EINVAL; } @@ -956,8 +963,8 @@ qca_spi_probe(struct spi_device *spi) } if (register_netdev(qcaspi_devs)) { - dev_info(&spi->dev, "Unable to register net device %s\n", - qcaspi_devs->name); + dev_err(&spi->dev, "Unable to register net device %s\n", + qcaspi_devs->name); free_netdev(qcaspi_devs); return -EFAULT; } diff --git a/drivers/net/ethernet/qualcomm/qca_spi.h b/drivers/net/ethernet/qualcomm/qca_spi.h index fc4beb1b32d1a070a101b3c48cc092bd14561150..fc0e98726b3613ddd3774169fa13aa6099a5c6e5 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.h +++ b/drivers/net/ethernet/qualcomm/qca_spi.h @@ -83,11 +83,6 @@ struct qcaspi { struct tx_ring txr; struct qcaspi_stats stats; - struct spi_message spi_msg1; - struct spi_message spi_msg2; - struct spi_transfer spi_xfer1; - struct spi_transfer spi_xfer2[2]; - u8 *rx_buffer; u32 buffer_size; u8 sync; diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h index eadfc97d70b969dc81d71d9c55fd211a6133819c..a800e2aa904a64f0328e12513d4670ff4feb19f8 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h @@ -110,6 +110,11 @@ struct rmnet_priv { void __rcu *qos_info; }; +enum rmnet_dl_marker_prio { + RMNET_PERF, + RMNET_SHS, +}; + enum rmnet_trace_func { RMNET_MODULE, NW_STACK_MODULE, diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h index 3db9038446307175ba60cd2b4562db1cc3781e8b..4e1aa2d4df3b4f9e864bf414d33db059dcf8cb8c 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h @@ -115,6 +115,7 @@ struct rmnet_map_dl_ind_trl { } __aligned(1); struct rmnet_map_dl_ind { + u8 priority; void (*dl_hdr_handler)(struct rmnet_map_dl_ind_hdr *); void (*dl_trl_handler)(struct rmnet_map_dl_ind_trl *); struct list_head list; diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c index 56457f72a3c675ab328a6a842ded9328f910ea67..8107da7de386e853fda56b8613eb4ed394368dfc 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c @@ -270,11 +270,38 @@ void rmnet_map_cmd_init(struct rmnet_port *port) int rmnet_map_dl_ind_register(struct rmnet_port *port, struct rmnet_map_dl_ind *dl_ind) { + struct rmnet_map_dl_ind *dl_ind_iterator; + bool empty_ind_list = true; + if (!port || !dl_ind || !dl_ind->dl_hdr_handler || !dl_ind->dl_trl_handler) return -EINVAL; - list_add_rcu(&dl_ind->list, &port->dl_list); + list_for_each_entry_rcu(dl_ind_iterator, &port->dl_list, list) { + empty_ind_list = false; + if (dl_ind_iterator->priority < dl_ind->priority) { + if (dl_ind_iterator->list.next) { + if (dl_ind->priority + < list_entry_rcu(dl_ind_iterator->list.next, + typeof(*dl_ind_iterator), list)->priority) { + list_add_rcu(&dl_ind->list, + &dl_ind_iterator->list); + break; + } + } else { + list_add_rcu(&dl_ind->list, + &dl_ind_iterator->list); + break; + } + } else { + list_add_tail_rcu(&dl_ind->list, + &dl_ind_iterator->list); + break; + } + } + + if (empty_ind_list) + list_add_rcu(&dl_ind->list, &port->dl_list); return 0; } diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index b98fcc9e93e5ace2df1ea69f06136f074cd33b77..f7e540eeb877ebbc2128a422a9b79d5b0f107c0d 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -329,6 +329,7 @@ static const struct pci_device_id rtl8169_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8161), 0, 0, RTL_CFG_1 }, { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167), 0, 0, RTL_CFG_0 }, { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), 0, 0, RTL_CFG_1 }, + { PCI_DEVICE(PCI_VENDOR_ID_NCUBE, 0x8168), 0, 0, RTL_CFG_1 }, { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), 0, 0, RTL_CFG_0 }, { PCI_VENDOR_ID_DLINK, 0x4300, PCI_VENDOR_ID_DLINK, 0x4b10, 0, 0, RTL_CFG_1 }, @@ -759,7 +760,7 @@ struct rtl8169_tc_offsets { }; enum rtl_flag { - RTL_FLAG_TASK_ENABLED, + RTL_FLAG_TASK_ENABLED = 0, RTL_FLAG_TASK_SLOW_PENDING, RTL_FLAG_TASK_RESET_PENDING, RTL_FLAG_TASK_PHY_PENDING, @@ -7656,7 +7657,8 @@ static int rtl8169_close(struct net_device *dev) rtl8169_update_counters(dev); rtl_lock_work(tp); - clear_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags); + /* Clear all task flags */ + bitmap_zero(tp->wk.flags, RTL_FLAG_MAX); rtl8169_down(dev); rtl_unlock_work(tp); @@ -7837,7 +7839,9 @@ static void rtl8169_net_suspend(struct net_device *dev) rtl_lock_work(tp); napi_disable(&tp->napi); - clear_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags); + /* Clear all task flags */ + bitmap_zero(tp->wk.flags, RTL_FLAG_MAX); + rtl_unlock_work(tp); rtl_pll_power_down(tp); diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index fdf30bfa403bf416572fa45ac3dde48f1e92cded..e87a779bfcfe5a38ba91ce13f4224e27ce19c022 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -959,6 +959,13 @@ static void ravb_adjust_link(struct net_device *ndev) struct ravb_private *priv = netdev_priv(ndev); struct phy_device *phydev = ndev->phydev; bool new_state = false; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + /* Disable TX and RX right over here, if E-MAC change is ignored */ + if (priv->no_avb_link) + ravb_rcv_snd_disable(ndev); if (phydev->link) { if (phydev->duplex != priv->duplex) { @@ -976,18 +983,21 @@ static void ravb_adjust_link(struct net_device *ndev) ravb_modify(ndev, ECMR, ECMR_TXF, 0); new_state = true; priv->link = phydev->link; - if (priv->no_avb_link) - ravb_rcv_snd_enable(ndev); } } else if (priv->link) { new_state = true; priv->link = 0; priv->speed = 0; priv->duplex = -1; - if (priv->no_avb_link) - ravb_rcv_snd_disable(ndev); } + /* Enable TX and RX right over here, if E-MAC change is ignored */ + if (priv->no_avb_link && phydev->link) + ravb_rcv_snd_enable(ndev); + + mmiowb(); + spin_unlock_irqrestore(&priv->lock, flags); + if (new_state && netif_msg_link(priv)) phy_print_status(phydev); } @@ -1094,52 +1104,18 @@ static int ravb_get_link_ksettings(struct net_device *ndev, static int ravb_set_link_ksettings(struct net_device *ndev, const struct ethtool_link_ksettings *cmd) { - struct ravb_private *priv = netdev_priv(ndev); - unsigned long flags; - int error; - if (!ndev->phydev) return -ENODEV; - spin_lock_irqsave(&priv->lock, flags); - - /* Disable TX and RX */ - ravb_rcv_snd_disable(ndev); - - error = phy_ethtool_ksettings_set(ndev->phydev, cmd); - if (error) - goto error_exit; - - if (cmd->base.duplex == DUPLEX_FULL) - priv->duplex = 1; - else - priv->duplex = 0; - - ravb_set_duplex(ndev); - -error_exit: - mdelay(1); - - /* Enable TX and RX */ - ravb_rcv_snd_enable(ndev); - - mmiowb(); - spin_unlock_irqrestore(&priv->lock, flags); - - return error; + return phy_ethtool_ksettings_set(ndev->phydev, cmd); } static int ravb_nway_reset(struct net_device *ndev) { - struct ravb_private *priv = netdev_priv(ndev); int error = -ENODEV; - unsigned long flags; - if (ndev->phydev) { - spin_lock_irqsave(&priv->lock, flags); + if (ndev->phydev) error = phy_start_aneg(ndev->phydev); - spin_unlock_irqrestore(&priv->lock, flags); - } return error; } diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 38080e95a82dccc6286a0cd40829be35ac9612ee..abfb9faadbc40b10a36dfba58d2801e603961bcb 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -1821,8 +1821,15 @@ static void sh_eth_adjust_link(struct net_device *ndev) { struct sh_eth_private *mdp = netdev_priv(ndev); struct phy_device *phydev = ndev->phydev; + unsigned long flags; int new_state = 0; + spin_lock_irqsave(&mdp->lock, flags); + + /* Disable TX and RX right over here, if E-MAC change is ignored */ + if (mdp->cd->no_psr || mdp->no_ether_link) + sh_eth_rcv_snd_disable(ndev); + if (phydev->link) { if (phydev->duplex != mdp->duplex) { new_state = 1; @@ -1841,18 +1848,21 @@ static void sh_eth_adjust_link(struct net_device *ndev) sh_eth_modify(ndev, ECMR, ECMR_TXF, 0); new_state = 1; mdp->link = phydev->link; - if (mdp->cd->no_psr || mdp->no_ether_link) - sh_eth_rcv_snd_enable(ndev); } } else if (mdp->link) { new_state = 1; mdp->link = 0; mdp->speed = 0; mdp->duplex = -1; - if (mdp->cd->no_psr || mdp->no_ether_link) - sh_eth_rcv_snd_disable(ndev); } + /* Enable TX and RX right over here, if E-MAC change is ignored */ + if ((mdp->cd->no_psr || mdp->no_ether_link) && phydev->link) + sh_eth_rcv_snd_enable(ndev); + + mmiowb(); + spin_unlock_irqrestore(&mdp->lock, flags); + if (new_state && netif_msg_link(mdp)) phy_print_status(phydev); } @@ -1933,39 +1943,10 @@ static int sh_eth_get_link_ksettings(struct net_device *ndev, static int sh_eth_set_link_ksettings(struct net_device *ndev, const struct ethtool_link_ksettings *cmd) { - struct sh_eth_private *mdp = netdev_priv(ndev); - unsigned long flags; - int ret; - if (!ndev->phydev) return -ENODEV; - spin_lock_irqsave(&mdp->lock, flags); - - /* disable tx and rx */ - sh_eth_rcv_snd_disable(ndev); - - ret = phy_ethtool_ksettings_set(ndev->phydev, cmd); - if (ret) - goto error_exit; - - if (cmd->base.duplex == DUPLEX_FULL) - mdp->duplex = 1; - else - mdp->duplex = 0; - - if (mdp->cd->set_duplex) - mdp->cd->set_duplex(ndev); - -error_exit: - mdelay(1); - - /* enable tx and rx */ - sh_eth_rcv_snd_enable(ndev); - - spin_unlock_irqrestore(&mdp->lock, flags); - - return ret; + return phy_ethtool_ksettings_set(ndev->phydev, cmd); } /* If it is ever necessary to increase SH_ETH_REG_DUMP_MAX_REGS, the @@ -2156,18 +2137,10 @@ static void sh_eth_get_regs(struct net_device *ndev, struct ethtool_regs *regs, static int sh_eth_nway_reset(struct net_device *ndev) { - struct sh_eth_private *mdp = netdev_priv(ndev); - unsigned long flags; - int ret; - if (!ndev->phydev) return -ENODEV; - spin_lock_irqsave(&mdp->lock, flags); - ret = phy_start_aneg(ndev->phydev); - spin_unlock_irqrestore(&mdp->lock, flags); - - return ret; + return phy_start_aneg(ndev->phydev); } static u32 sh_eth_get_msglevel(struct net_device *ndev) diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index 97035766c291b0a9df2734d1f97d88ac72d5f688..5790cd61436d0b2ca73eeb1d1eeab1b759083784 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -111,7 +111,7 @@ config DWMAC_ROCKCHIP config DWMAC_SOCFPGA tristate "SOCFPGA dwmac support" default ARCH_SOCFPGA - depends on OF && (ARCH_SOCFPGA || COMPILE_TEST) + depends on OF && (ARCH_SOCFPGA || ARCH_STRATIX10 || COMPILE_TEST) select MFD_SYSCON help Support for ethernet controller on Altera SOCFPGA diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c index 6e359572b9f0ea53ed46b553fb1cb51273415f57..5b3b06a0a3bf53e1eac9572ae8d14add0c3835e7 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c @@ -55,6 +55,7 @@ struct socfpga_dwmac { struct device *dev; struct regmap *sys_mgr_base_addr; struct reset_control *stmmac_rst; + struct reset_control *stmmac_ocp_rst; void __iomem *splitter_base; bool f2h_ptp_ref_clk; struct tse_pcs pcs; @@ -262,8 +263,8 @@ static int socfpga_dwmac_set_phy_mode(struct socfpga_dwmac *dwmac) val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII; /* Assert reset to the enet controller before changing the phy mode */ - if (dwmac->stmmac_rst) - reset_control_assert(dwmac->stmmac_rst); + reset_control_assert(dwmac->stmmac_ocp_rst); + reset_control_assert(dwmac->stmmac_rst); regmap_read(sys_mgr_base_addr, reg_offset, &ctrl); ctrl &= ~(SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << reg_shift); @@ -288,8 +289,8 @@ static int socfpga_dwmac_set_phy_mode(struct socfpga_dwmac *dwmac) /* Deassert reset for the phy configuration to be sampled by * the enet controller, and operation to start in requested mode */ - if (dwmac->stmmac_rst) - reset_control_deassert(dwmac->stmmac_rst); + reset_control_deassert(dwmac->stmmac_ocp_rst); + reset_control_deassert(dwmac->stmmac_rst); if (phymode == PHY_INTERFACE_MODE_SGMII) { if (tse_pcs_init(dwmac->pcs.tse_pcs_base, &dwmac->pcs) != 0) { dev_err(dwmac->dev, "Unable to initialize TSE PCS"); @@ -324,6 +325,15 @@ static int socfpga_dwmac_probe(struct platform_device *pdev) goto err_remove_config_dt; } + dwmac->stmmac_ocp_rst = devm_reset_control_get_optional(dev, "stmmaceth-ocp"); + if (IS_ERR(dwmac->stmmac_ocp_rst)) { + ret = PTR_ERR(dwmac->stmmac_ocp_rst); + dev_err(dev, "error getting reset control of ocp %d\n", ret); + goto err_remove_config_dt; + } + + reset_control_deassert(dwmac->stmmac_ocp_rst); + ret = socfpga_dwmac_parse_data(dwmac, dev); if (ret) { dev_err(dev, "Unable to parse OF data\n"); diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index 4bb561856af53c0165e1d052a7ebfa2bd279ce68..47a096134043c68037827789ced6f872eb1437d9 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -1387,6 +1387,10 @@ static int emac_devioctl(struct net_device *ndev, struct ifreq *ifrq, int cmd) static int match_first_device(struct device *dev, void *data) { + if (dev->parent && dev->parent->of_node) + return of_device_is_compatible(dev->parent->of_node, + "ti,davinci_mdio"); + return !strncmp(dev_name(dev), "davinci_mdio", 12); } diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c index 16c3bfbe19928dfb56b2719490d0b401fae2ee5e..757a3b37ae8a8af8077001d548b65fe862d03c2d 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c @@ -218,6 +218,7 @@ int axienet_mdio_setup(struct axienet_local *lp, struct device_node *np) ret = of_mdiobus_register(bus, np1); if (ret) { mdiobus_free(bus); + lp->mii_bus = NULL; return ret; } return 0; diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 78a6414c5fd994445c7e530065bd6cfa7e5ad213..7d94a78425576c5337fe0445826f887430eb8ac3 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -89,10 +89,6 @@ static const char banner[] __initconst = KERN_INFO \ "AX.25: bpqether driver version 004\n"; -static char bcast_addr[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; - -static char bpq_eth_addr[6]; - static int bpq_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *); static int bpq_device_event(struct notifier_block *, unsigned long, void *); @@ -515,8 +511,8 @@ static int bpq_new_device(struct net_device *edev) bpq->ethdev = edev; bpq->axdev = ndev; - memcpy(bpq->dest_addr, bcast_addr, sizeof(bpq_eth_addr)); - memcpy(bpq->acpt_addr, bcast_addr, sizeof(bpq_eth_addr)); + eth_broadcast_addr(bpq->dest_addr); + eth_broadcast_addr(bpq->acpt_addr); err = register_netdevice(ndev); if (err) diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 6a77ef38c5495cc62b4c547c95f42a22051cdf2a..aba16d81e9bbac683b3b742be3c3edd88ffbffbe 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -1895,11 +1896,15 @@ static int netvsc_register_vf(struct net_device *vf_netdev) { struct net_device *ndev; struct net_device_context *net_device_ctx; + struct device *pdev = vf_netdev->dev.parent; struct netvsc_device *netvsc_dev; if (vf_netdev->addr_len != ETH_ALEN) return NOTIFY_DONE; + if (!pdev || !dev_is_pci(pdev) || dev_is_pf(pdev)) + return NOTIFY_DONE; + /* * We will use the MAC address to locate the synthetic interface to * associate with the VF interface. If we don't find a matching @@ -2039,6 +2044,16 @@ static int netvsc_probe(struct hv_device *dev, memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN); + /* We must get rtnl lock before scheduling nvdev->subchan_work, + * otherwise netvsc_subchan_work() can get rtnl lock first and wait + * all subchannels to show up, but that may not happen because + * netvsc_probe() can't get rtnl lock and as a result vmbus_onoffer() + * -> ... -> device_add() -> ... -> __device_attach() can't get + * the device lock, so all the subchannels can't be processed -- + * finally netvsc_subchan_work() hangs for ever. + */ + rtnl_lock(); + if (nvdev->num_chn > 1) schedule_work(&nvdev->subchan_work); @@ -2057,7 +2072,6 @@ static int netvsc_probe(struct hv_device *dev, else net->max_mtu = ETH_DATA_LEN; - rtnl_lock(); ret = register_netdevice(net); if (ret != 0) { pr_err("Unable to register netdev.\n"); diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index cb03a6ea076a66c7ca856e912ed42a97741e05da..17025d46bdac8412e32b96fc86aaa28afc6d75f0 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -1299,6 +1299,7 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev, /* setting up multiple channels failed */ net_device->max_chn = 1; net_device->num_chn = 1; + return net_device; err_dev_remv: rndis_filter_device_remove(dev, net_device); diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 548d9d026a85e2ff0e329f0f61454f555ab1a522..5c48bdb6f6787acbb74819ad7601ad302f644623 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -940,7 +940,7 @@ at86rf230_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) static int at86rf230_ed(struct ieee802154_hw *hw, u8 *level) { - BUG_ON(!level); + WARN_ON(!level); *level = 0xbe; return 0; } @@ -1121,8 +1121,7 @@ at86rf230_set_hw_addr_filt(struct ieee802154_hw *hw, if (changed & IEEE802154_AFILT_SADDR_CHANGED) { u16 addr = le16_to_cpu(filt->short_addr); - dev_vdbg(&lp->spi->dev, - "at86rf230_set_hw_addr_filt called for saddr\n"); + dev_vdbg(&lp->spi->dev, "%s called for saddr\n", __func__); __at86rf230_write(lp, RG_SHORT_ADDR_0, addr); __at86rf230_write(lp, RG_SHORT_ADDR_1, addr >> 8); } @@ -1130,8 +1129,7 @@ at86rf230_set_hw_addr_filt(struct ieee802154_hw *hw, if (changed & IEEE802154_AFILT_PANID_CHANGED) { u16 pan = le16_to_cpu(filt->pan_id); - dev_vdbg(&lp->spi->dev, - "at86rf230_set_hw_addr_filt called for pan id\n"); + dev_vdbg(&lp->spi->dev, "%s called for pan id\n", __func__); __at86rf230_write(lp, RG_PAN_ID_0, pan); __at86rf230_write(lp, RG_PAN_ID_1, pan >> 8); } @@ -1140,15 +1138,13 @@ at86rf230_set_hw_addr_filt(struct ieee802154_hw *hw, u8 i, addr[8]; memcpy(addr, &filt->ieee_addr, 8); - dev_vdbg(&lp->spi->dev, - "at86rf230_set_hw_addr_filt called for IEEE addr\n"); + dev_vdbg(&lp->spi->dev, "%s called for IEEE addr\n", __func__); for (i = 0; i < 8; i++) __at86rf230_write(lp, RG_IEEE_ADDR_0 + i, addr[i]); } if (changed & IEEE802154_AFILT_PANC_CHANGED) { - dev_vdbg(&lp->spi->dev, - "at86rf230_set_hw_addr_filt called for panc change\n"); + dev_vdbg(&lp->spi->dev, "%s called for panc change\n", __func__); if (filt->pan_coord) at86rf230_write_subreg(lp, SR_AACK_I_AM_COORD, 1); else @@ -1252,7 +1248,6 @@ at86rf230_set_cca_mode(struct ieee802154_hw *hw, return at86rf230_write_subreg(lp, SR_CCA_MODE, val); } - static int at86rf230_set_cca_ed_level(struct ieee802154_hw *hw, s32 mbm) { diff --git a/drivers/net/ieee802154/fakelb.c b/drivers/net/ieee802154/fakelb.c index 0d673f7682ee065223b64462bc2c4df0a03826a0..176395e4b7bb0ca628bdd22b4f13a23e425bfae2 100644 --- a/drivers/net/ieee802154/fakelb.c +++ b/drivers/net/ieee802154/fakelb.c @@ -49,7 +49,7 @@ struct fakelb_phy { static int fakelb_hw_ed(struct ieee802154_hw *hw, u8 *level) { - BUG_ON(!level); + WARN_ON(!level); *level = 0xbe; return 0; diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index e7f7a1a002ee05bace0a05aab920eb3537a1d40b..58133c9f701b8cc65d0fcffa566511f691c5a5c3 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c @@ -73,10 +73,23 @@ static int ipvlan_set_port_mode(struct ipvl_port *port, u16 nval) { struct ipvl_dev *ipvlan; struct net_device *mdev = port->dev; - int err = 0; + unsigned int flags; + int err; ASSERT_RTNL(); if (port->mode != nval) { + list_for_each_entry(ipvlan, &port->ipvlans, pnode) { + flags = ipvlan->dev->flags; + if (nval == IPVLAN_MODE_L3 || nval == IPVLAN_MODE_L3S) { + err = dev_change_flags(ipvlan->dev, + flags | IFF_NOARP); + } else { + err = dev_change_flags(ipvlan->dev, + flags & ~IFF_NOARP); + } + if (unlikely(err)) + goto fail; + } if (nval == IPVLAN_MODE_L3S) { /* New mode is L3S */ err = ipvlan_register_nf_hook(read_pnet(&port->pnet)); @@ -84,21 +97,28 @@ static int ipvlan_set_port_mode(struct ipvl_port *port, u16 nval) mdev->l3mdev_ops = &ipvl_l3mdev_ops; mdev->priv_flags |= IFF_L3MDEV_MASTER; } else - return err; + goto fail; } else if (port->mode == IPVLAN_MODE_L3S) { /* Old mode was L3S */ mdev->priv_flags &= ~IFF_L3MDEV_MASTER; ipvlan_unregister_nf_hook(read_pnet(&port->pnet)); mdev->l3mdev_ops = NULL; } - list_for_each_entry(ipvlan, &port->ipvlans, pnode) { - if (nval == IPVLAN_MODE_L3 || nval == IPVLAN_MODE_L3S) - ipvlan->dev->flags |= IFF_NOARP; - else - ipvlan->dev->flags &= ~IFF_NOARP; - } port->mode = nval; } + return 0; + +fail: + /* Undo the flags changes that have been done so far. */ + list_for_each_entry_continue_reverse(ipvlan, &port->ipvlans, pnode) { + flags = ipvlan->dev->flags; + if (port->mode == IPVLAN_MODE_L3 || + port->mode == IPVLAN_MODE_L3S) + dev_change_flags(ipvlan->dev, flags | IFF_NOARP); + else + dev_change_flags(ipvlan->dev, flags & ~IFF_NOARP); + } + return err; } diff --git a/drivers/net/phy/mdio-mux-bcm-iproc.c b/drivers/net/phy/mdio-mux-bcm-iproc.c index 0c5b68e7da51aa8d0c7c73e7c6b3cc632b1e3510..9b31670548433276a431458b69e515aa62debe7f 100644 --- a/drivers/net/phy/mdio-mux-bcm-iproc.c +++ b/drivers/net/phy/mdio-mux-bcm-iproc.c @@ -22,7 +22,7 @@ #include #include -#define MDIO_PARAM_OFFSET 0x00 +#define MDIO_PARAM_OFFSET 0x23c #define MDIO_PARAM_MIIM_CYCLE 29 #define MDIO_PARAM_INTERNAL_SEL 25 #define MDIO_PARAM_BUS_ID 22 @@ -30,20 +30,22 @@ #define MDIO_PARAM_PHY_ID 16 #define MDIO_PARAM_PHY_DATA 0 -#define MDIO_READ_OFFSET 0x04 +#define MDIO_READ_OFFSET 0x240 #define MDIO_READ_DATA_MASK 0xffff -#define MDIO_ADDR_OFFSET 0x08 +#define MDIO_ADDR_OFFSET 0x244 -#define MDIO_CTRL_OFFSET 0x0C +#define MDIO_CTRL_OFFSET 0x248 #define MDIO_CTRL_WRITE_OP 0x1 #define MDIO_CTRL_READ_OP 0x2 -#define MDIO_STAT_OFFSET 0x10 +#define MDIO_STAT_OFFSET 0x24c #define MDIO_STAT_DONE 1 #define BUS_MAX_ADDR 32 #define EXT_BUS_START_ADDR 16 +#define MDIO_REG_ADDR_SPACE_SIZE 0x250 + struct iproc_mdiomux_desc { void *mux_handle; void __iomem *base; @@ -169,6 +171,14 @@ static int mdio_mux_iproc_probe(struct platform_device *pdev) md->dev = &pdev->dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res->start & 0xfff) { + /* For backward compatibility in case the + * base address is specified with an offset. + */ + dev_info(&pdev->dev, "fix base address in dt-blob\n"); + res->start &= ~0xfff; + res->end = res->start + MDIO_REG_ADDR_SPACE_SIZE - 1; + } md->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(md->base)) { dev_err(&pdev->dev, "failed to ioremap register\n"); diff --git a/drivers/net/phy/xilinx_gmii2rgmii.c b/drivers/net/phy/xilinx_gmii2rgmii.c index 2e5150b0b8d52c5dd784a3df1818962d64972898..7a14e8170e8263fe84f362f4e04e313e2f3d312b 100644 --- a/drivers/net/phy/xilinx_gmii2rgmii.c +++ b/drivers/net/phy/xilinx_gmii2rgmii.c @@ -40,8 +40,11 @@ static int xgmiitorgmii_read_status(struct phy_device *phydev) { struct gmii2rgmii *priv = phydev->priv; u16 val = 0; + int err; - priv->phy_drv->read_status(phydev); + err = priv->phy_drv->read_status(phydev); + if (err < 0) + return err; val = mdiobus_read(phydev->mdio.bus, priv->addr, XILINX_GMII2RGMII_REG); val &= ~XILINX_GMII2RGMII_SPEED_MASK; @@ -81,6 +84,11 @@ static int xgmiitorgmii_probe(struct mdio_device *mdiodev) return -EPROBE_DEFER; } + if (!priv->phy_dev->drv) { + dev_info(dev, "Attached phy not ready\n"); + return -EPROBE_DEFER; + } + priv->addr = mdiodev->addr; priv->phy_drv = priv->phy_dev->drv; memcpy(&priv->conv_phy_drv, priv->phy_dev->drv, diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index 71e2aef6b7a1b5cdb052fed4aeec2a843a1a9a4d..951892da3352e3b5f303d3f8c8659cc6031323cc 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -429,6 +429,9 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev, if (!skb) goto out; + if (skb_mac_header_len(skb) < ETH_HLEN) + goto drop; + if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) goto drop; diff --git a/drivers/net/ppp/pppolac.c b/drivers/net/ppp/pppolac.c index 95cc6be54ad5a058be577398c918c9f7511df690..9a3564cc7ca930619dddd397afbe6c25986b5548 100644 --- a/drivers/net/ppp/pppolac.c +++ b/drivers/net/ppp/pppolac.c @@ -83,7 +83,7 @@ static int pppolac_recv_core(struct sock *sk_udp, struct sk_buff *skb) /* Put it back if it is a control packet. */ if (skb->data[sizeof(struct udphdr)] & L2TP_CONTROL_BIT) - return opt->backlog_rcv(sk_udp, skb); + return 2; /* Skip UDP header. */ skb_pull(skb, sizeof(struct udphdr)); @@ -190,9 +190,10 @@ static int pppolac_recv_core(struct sock *sk_udp, struct sk_buff *skb) static int pppolac_recv(struct sock *sk_udp, struct sk_buff *skb) { + int retval; sock_hold(sk_udp); - sk_receive_skb(sk_udp, skb, 0); - return 0; + retval = sk_receive_skb(sk_udp, skb, 0); + return (retval >> 1); } static struct sk_buff_head delivery_queue; diff --git a/drivers/net/tun.c b/drivers/net/tun.c index e34ea5a2a69246a2566647ab0421334ff1a3b616..f34f26d2a97a56ecd5afe72d323433c0520a412c 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -534,14 +534,6 @@ static void tun_queue_purge(struct tun_file *tfile) skb_queue_purge(&tfile->sk.sk_error_queue); } -static void tun_cleanup_tx_array(struct tun_file *tfile) -{ - if (tfile->tx_array.ring.queue) { - skb_array_cleanup(&tfile->tx_array); - memset(&tfile->tx_array, 0, sizeof(tfile->tx_array)); - } -} - static void __tun_detach(struct tun_file *tfile, bool clean) { struct tun_file *ntfile; @@ -583,7 +575,7 @@ static void __tun_detach(struct tun_file *tfile, bool clean) tun->dev->reg_state == NETREG_REGISTERED) unregister_netdevice(tun->dev); } - tun_cleanup_tx_array(tfile); + skb_array_cleanup(&tfile->tx_array); sock_put(&tfile->sk); } } @@ -623,13 +615,11 @@ static void tun_detach_all(struct net_device *dev) /* Drop read queue */ tun_queue_purge(tfile); sock_put(&tfile->sk); - tun_cleanup_tx_array(tfile); } list_for_each_entry_safe(tfile, tmp, &tun->disabled, next) { tun_enable_queue(tfile); tun_queue_purge(tfile); sock_put(&tfile->sk); - tun_cleanup_tx_array(tfile); } BUG_ON(tun->numdisabled != 0); @@ -675,7 +665,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file, bool skip_filte } if (!tfile->detached && - skb_array_init(&tfile->tx_array, dev->tx_queue_len, GFP_KERNEL)) { + skb_array_resize(&tfile->tx_array, dev->tx_queue_len, GFP_KERNEL)) { err = -ENOMEM; goto out; } @@ -2634,6 +2624,11 @@ static int tun_chr_open(struct inode *inode, struct file * file) &tun_proto, 0); if (!tfile) return -ENOMEM; + if (skb_array_init(&tfile->tx_array, 0, GFP_KERNEL)) { + sk_free(&tfile->sk); + return -ENOMEM; + } + RCU_INIT_POINTER(tfile->tun, NULL); tfile->flags = 0; tfile->ifindex = 0; @@ -2654,8 +2649,6 @@ static int tun_chr_open(struct inode *inode, struct file * file) sock_set_flag(&tfile->sk, SOCK_ZEROCOPY); - memset(&tfile->tx_array, 0, sizeof(tfile->tx_array)); - return 0; } diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 6d3811c869fdddeadd3110f320b2ee5cb2c18f96..c5d4b35bb72aef97ef263843f8b6eb42cbc7acc4 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -1205,13 +1205,13 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x1199, 0x9061, 8)}, /* Sierra Wireless Modem */ {QMI_FIXED_INTF(0x1199, 0x9063, 8)}, /* Sierra Wireless EM7305 */ {QMI_FIXED_INTF(0x1199, 0x9063, 10)}, /* Sierra Wireless EM7305 */ - {QMI_FIXED_INTF(0x1199, 0x9071, 8)}, /* Sierra Wireless MC74xx */ - {QMI_FIXED_INTF(0x1199, 0x9071, 10)}, /* Sierra Wireless MC74xx */ - {QMI_FIXED_INTF(0x1199, 0x9079, 8)}, /* Sierra Wireless EM74xx */ - {QMI_FIXED_INTF(0x1199, 0x9079, 10)}, /* Sierra Wireless EM74xx */ - {QMI_FIXED_INTF(0x1199, 0x907b, 8)}, /* Sierra Wireless EM74xx */ - {QMI_FIXED_INTF(0x1199, 0x907b, 10)}, /* Sierra Wireless EM74xx */ - {QMI_FIXED_INTF(0x1199, 0x9091, 8)}, /* Sierra Wireless EM7565 */ + {QMI_QUIRK_SET_DTR(0x1199, 0x9071, 8)}, /* Sierra Wireless MC74xx */ + {QMI_QUIRK_SET_DTR(0x1199, 0x9071, 10)},/* Sierra Wireless MC74xx */ + {QMI_QUIRK_SET_DTR(0x1199, 0x9079, 8)}, /* Sierra Wireless EM74xx */ + {QMI_QUIRK_SET_DTR(0x1199, 0x9079, 10)},/* Sierra Wireless EM74xx */ + {QMI_QUIRK_SET_DTR(0x1199, 0x907b, 8)}, /* Sierra Wireless EM74xx */ + {QMI_QUIRK_SET_DTR(0x1199, 0x907b, 10)},/* Sierra Wireless EM74xx */ + {QMI_QUIRK_SET_DTR(0x1199, 0x9091, 8)}, /* Sierra Wireless EM7565 */ {QMI_FIXED_INTF(0x1bbb, 0x011e, 4)}, /* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */ {QMI_FIXED_INTF(0x1bbb, 0x0203, 2)}, /* Alcatel L800MA */ {QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */ @@ -1245,7 +1245,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x413c, 0x81b3, 8)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card (rev3) */ {QMI_FIXED_INTF(0x413c, 0x81b6, 8)}, /* Dell Wireless 5811e */ {QMI_FIXED_INTF(0x413c, 0x81b6, 10)}, /* Dell Wireless 5811e */ - {QMI_FIXED_INTF(0x413c, 0x81d7, 1)}, /* Dell Wireless 5821e */ + {QMI_FIXED_INTF(0x413c, 0x81d7, 0)}, /* Dell Wireless 5821e */ {QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)}, /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */ {QMI_FIXED_INTF(0x03f0, 0x9d1d, 1)}, /* HP lt4120 Snapdragon X5 LTE */ {QMI_FIXED_INTF(0x22de, 0x9061, 3)}, /* WeTelecom WPD-600N */ diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index 5f565bd574da3bc7ce741e3b280a9ff5dece4352..48ba80a8ca5ce8e566931979edcff4bcfe47bc2e 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -681,7 +681,7 @@ static void rtl8150_set_multicast(struct net_device *netdev) (netdev->flags & IFF_ALLMULTI)) { rx_creg &= 0xfffe; rx_creg |= 0x0002; - dev_info(&netdev->dev, "%s: allmulti set\n", netdev->name); + dev_dbg(&netdev->dev, "%s: allmulti set\n", netdev->name); } else { /* ~RX_MULTICAST, ~RX_PROMISCUOUS */ rx_creg &= 0x00fc; diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index 7a6a1fe793090b8e28f5ef075f5ebc2ad385b5eb..05553d2524469f97e4a02bb48f43f6820ad2b3e5 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c @@ -82,6 +82,9 @@ static bool turbo_mode = true; module_param(turbo_mode, bool, 0644); MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction"); +static int smsc75xx_link_ok_nopm(struct usbnet *dev); +static int smsc75xx_phy_gig_workaround(struct usbnet *dev); + static int __must_check __smsc75xx_read_reg(struct usbnet *dev, u32 index, u32 *data, int in_pm) { @@ -852,6 +855,9 @@ static int smsc75xx_phy_initialize(struct usbnet *dev) return -EIO; } + /* phy workaround for gig link */ + smsc75xx_phy_gig_workaround(dev); + smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); @@ -987,6 +993,62 @@ static int smsc75xx_wait_ready(struct usbnet *dev, int in_pm) return -EIO; } +static int smsc75xx_phy_gig_workaround(struct usbnet *dev) +{ + struct mii_if_info *mii = &dev->mii; + int ret = 0, timeout = 0; + u32 buf, link_up = 0; + + /* Set the phy in Gig loopback */ + smsc75xx_mdio_write(dev->net, mii->phy_id, MII_BMCR, 0x4040); + + /* Wait for the link up */ + do { + link_up = smsc75xx_link_ok_nopm(dev); + usleep_range(10000, 20000); + timeout++; + } while ((!link_up) && (timeout < 1000)); + + if (timeout >= 1000) { + netdev_warn(dev->net, "Timeout waiting for PHY link up\n"); + return -EIO; + } + + /* phy reset */ + ret = smsc75xx_read_reg(dev, PMT_CTL, &buf); + if (ret < 0) { + netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n", ret); + return ret; + } + + buf |= PMT_CTL_PHY_RST; + + ret = smsc75xx_write_reg(dev, PMT_CTL, buf); + if (ret < 0) { + netdev_warn(dev->net, "Failed to write PMT_CTL: %d\n", ret); + return ret; + } + + timeout = 0; + do { + usleep_range(10000, 20000); + ret = smsc75xx_read_reg(dev, PMT_CTL, &buf); + if (ret < 0) { + netdev_warn(dev->net, "Failed to read PMT_CTL: %d\n", + ret); + return ret; + } + timeout++; + } while ((buf & PMT_CTL_PHY_RST) && (timeout < 100)); + + if (timeout >= 100) { + netdev_warn(dev->net, "timeout waiting for PHY Reset\n"); + return -EIO; + } + + return 0; +} + static int smsc75xx_reset(struct usbnet *dev) { struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index 33df76405b869a8504415fc8529222616bac9586..18b648648adb2e5676fadf3fc66721e7f84ac972 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -192,7 +192,7 @@ static int uhdlc_init(struct ucc_hdlc_private *priv) priv->ucc_pram_offset = qe_muram_alloc(sizeof(struct ucc_hdlc_param), ALIGNMENT_OF_UCC_HDLC_PRAM); - if (priv->ucc_pram_offset < 0) { + if (IS_ERR_VALUE(priv->ucc_pram_offset)) { dev_err(priv->dev, "Can not allocate MURAM for hdlc parameter.\n"); ret = -ENOMEM; goto free_tx_bd; @@ -228,14 +228,14 @@ static int uhdlc_init(struct ucc_hdlc_private *priv) /* Alloc riptr, tiptr */ riptr = qe_muram_alloc(32, 32); - if (riptr < 0) { + if (IS_ERR_VALUE(riptr)) { dev_err(priv->dev, "Cannot allocate MURAM mem for Receive internal temp data pointer\n"); ret = -ENOMEM; goto free_tx_skbuff; } tiptr = qe_muram_alloc(32, 32); - if (tiptr < 0) { + if (IS_ERR_VALUE(tiptr)) { dev_err(priv->dev, "Cannot allocate MURAM mem for Transmit internal temp data pointer\n"); ret = -ENOMEM; goto free_riptr; diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index 4698450c77d1ef8cac62c163e3e8f8c06b99dc13..bb43d176eb4e38ec875e37ac2f4985159bcdab04 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -1371,7 +1371,7 @@ static irqreturn_t lmc_interrupt (int irq, void *dev_instance) /*fold00*/ case 0x001: printk(KERN_WARNING "%s: Master Abort (naughty)\n", dev->name); break; - case 0x010: + case 0x002: printk(KERN_WARNING "%s: Target Abort (not so naughty)\n", dev->name); break; default: diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index df514507d3f12d259161a047ef9b85a3a7a0e31f..22003895f85484ac299b6138d24f16be5db85932 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2013 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -163,6 +164,8 @@ void ath10k_debug_print_hwfw_info(struct ath10k *ar) void ath10k_debug_print_board_info(struct ath10k *ar) { char boardinfo[100]; + const struct firmware *board; + u32 crc; if (ar->id.bmi_ids_valid) scnprintf(boardinfo, sizeof(boardinfo), "%d:%d", @@ -170,11 +173,16 @@ void ath10k_debug_print_board_info(struct ath10k *ar) else scnprintf(boardinfo, sizeof(boardinfo), "N/A"); + board = ar->normal_mode_fw.board; + if (!IS_ERR_OR_NULL(board)) + crc = crc32_le(0, board->data, board->size); + else + crc = 0; + ath10k_info(ar, "board_file api %d bmi_id %s crc32 %08x", ar->bd_api, boardinfo, - crc32_le(0, ar->normal_mode_fw.board->data, - ar->normal_mode_fw.board->size)); + crc); } void ath10k_debug_print_boot_info(struct ath10k *ar) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 0aeeb233af780469fcc907ba5ee0bb53086d606a..21642bab485a12d0a6cda34161b9e2821d456b5d 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -215,11 +215,12 @@ int ath10k_htt_rx_ring_refill(struct ath10k *ar) spin_lock_bh(&htt->rx_ring.lock); ret = ath10k_htt_rx_ring_fill_n(htt, (htt->rx_ring.fill_level - htt->rx_ring.fill_cnt)); - spin_unlock_bh(&htt->rx_ring.lock); if (ret) ath10k_htt_rx_ring_free(htt); + spin_unlock_bh(&htt->rx_ring.lock); + return ret; } @@ -231,7 +232,9 @@ void ath10k_htt_rx_free(struct ath10k_htt *htt) skb_queue_purge(&htt->rx_in_ord_compl_q); skb_queue_purge(&htt->tx_fetch_ind_q); + spin_lock_bh(&htt->rx_ring.lock); ath10k_htt_rx_ring_free(htt); + spin_unlock_bh(&htt->rx_ring.lock); dma_free_coherent(htt->ar->dev, (htt->rx_ring.size * diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index df11bb44998888c52632c72b856f06444be7a85b..cdcfb175ad9b8cf300af30a70bdaf3c234740b72 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3074,6 +3074,13 @@ static int ath10k_update_channel_list(struct ath10k *ar) passive = channel->flags & IEEE80211_CHAN_NO_IR; ch->passive = passive; + /* the firmware is ignoring the "radar" flag of the + * channel and is scanning actively using Probe Requests + * on "Radar detection"/DFS channels which are not + * marked as "available" + */ + ch->passive |= ch->chan_radar; + ch->freq = channel->center_freq; ch->band_center_freq1 = channel->center_freq; ch->min_power = 0; @@ -4008,6 +4015,7 @@ void ath10k_mac_tx_push_pending(struct ath10k *ar) rcu_read_unlock(); spin_unlock_bh(&ar->txqs_lock); } +EXPORT_SYMBOL(ath10k_mac_tx_push_pending); /************/ /* Scanning */ @@ -5923,8 +5931,19 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) ath10k_mac_max_vht_nss(vht_mcs_mask))); if (changed & IEEE80211_RC_BW_CHANGED) { - ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM peer bw %d\n", - sta->addr, bw); + enum wmi_phy_mode mode; + + mode = chan_to_phymode(&def); + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM peer bw %d phymode %d\n", + sta->addr, bw, mode); + + err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, + WMI_PEER_PHYMODE, mode); + if (err) { + ath10k_warn(ar, "failed to update STA %pM peer phymode %d: %d\n", + sta->addr, mode, err); + goto exit; + } err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, WMI_PEER_CHAN_WIDTH, bw); @@ -5965,6 +5984,7 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) sta->addr); } +exit: mutex_unlock(&ar->conf_mutex); } diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c index 03a69e5b11165753717517f098480306af881f26..da9dbf3ddaa5e5ec2c5c072641bc8d5cb963f7f4 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.c +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -30,6 +30,7 @@ #include "debug.h" #include "hif.h" #include "htc.h" +#include "mac.h" #include "targaddrs.h" #include "trace.h" #include "sdio.h" @@ -396,6 +397,7 @@ static int ath10k_sdio_mbox_rx_process_packet(struct ath10k *ar, int ret; payload_len = le16_to_cpu(htc_hdr->len); + skb->len = payload_len + sizeof(struct ath10k_htc_hdr); if (trailer_present) { trailer = skb->data + sizeof(*htc_hdr) + @@ -434,12 +436,14 @@ static int ath10k_sdio_mbox_rx_process_packets(struct ath10k *ar, enum ath10k_htc_ep_id id; int ret, i, *n_lookahead_local; u32 *lookaheads_local; + int lookahead_idx = 0; for (i = 0; i < ar_sdio->n_rx_pkts; i++) { lookaheads_local = lookaheads; n_lookahead_local = n_lookahead; - id = ((struct ath10k_htc_hdr *)&lookaheads[i])->eid; + id = ((struct ath10k_htc_hdr *) + &lookaheads[lookahead_idx++])->eid; if (id >= ATH10K_HTC_EP_COUNT) { ath10k_warn(ar, "invalid endpoint in look-ahead: %d\n", @@ -462,6 +466,7 @@ static int ath10k_sdio_mbox_rx_process_packets(struct ath10k *ar, /* Only read lookahead's from RX trailers * for the last packet in a bundle. */ + lookahead_idx--; lookaheads_local = NULL; n_lookahead_local = NULL; } @@ -1342,6 +1347,8 @@ static void ath10k_sdio_irq_handler(struct sdio_func *func) break; } while (time_before(jiffies, timeout) && !done); + ath10k_mac_tx_push_pending(ar); + sdio_claim_host(ar_sdio->func); if (ret && ret != -ECANCELED) diff --git a/drivers/net/wireless/ath/ath10k/trace.h b/drivers/net/wireless/ath/ath10k/trace.h index e0d00cef0bd8d27dc0ee9d964d4343f542efce41..5b974bb76e6ccd485298e85820b3ae78c44b9019 100644 --- a/drivers/net/wireless/ath/ath10k/trace.h +++ b/drivers/net/wireless/ath/ath10k/trace.h @@ -152,10 +152,9 @@ TRACE_EVENT(ath10k_log_dbg_dump, ); TRACE_EVENT(ath10k_wmi_cmd, - TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len, - int ret), + TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len), - TP_ARGS(ar, id, buf, buf_len, ret), + TP_ARGS(ar, id, buf, buf_len), TP_STRUCT__entry( __string(device, dev_name(ar->dev)) @@ -163,7 +162,6 @@ TRACE_EVENT(ath10k_wmi_cmd, __field(unsigned int, id) __field(size_t, buf_len) __dynamic_array(u8, buf, buf_len) - __field(int, ret) ), TP_fast_assign( @@ -171,17 +169,15 @@ TRACE_EVENT(ath10k_wmi_cmd, __assign_str(driver, dev_driver_string(ar->dev)); __entry->id = id; __entry->buf_len = buf_len; - __entry->ret = ret; memcpy(__get_dynamic_array(buf), buf, buf_len); ), TP_printk( - "%s %s id %d len %zu ret %d", + "%s %s id %d len %zu", __get_str(driver), __get_str(device), __entry->id, - __entry->buf_len, - __entry->ret + __entry->buf_len ) ); diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 7616c1c4bbd32a5f4cdf343fe8ece9a90bf2db22..b54001e97ced0fdaec6e8363b83e3dee77003d21 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -1451,6 +1451,11 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar) cfg->keep_alive_pattern_size = __cpu_to_le32(0); cfg->max_tdls_concurrent_sleep_sta = __cpu_to_le32(1); cfg->max_tdls_concurrent_buffer_sta = __cpu_to_le32(1); + cfg->wmi_send_separate = __cpu_to_le32(0); + cfg->num_ocb_vdevs = __cpu_to_le32(0); + cfg->num_ocb_channels = __cpu_to_le32(0); + cfg->num_ocb_schedules = __cpu_to_le32(0); + cfg->host_capab = __cpu_to_le32(0); ath10k_wmi_put_host_mem_chunks(ar, chunks); @@ -1481,10 +1486,10 @@ ath10k_wmi_tlv_op_gen_start_scan(struct ath10k *ar, bssid_len = arg->n_bssids * sizeof(struct wmi_mac_addr); ie_len = roundup(arg->ie_len, 4); len = (sizeof(*tlv) + sizeof(*cmd)) + - (arg->n_channels ? sizeof(*tlv) + chan_len : 0) + - (arg->n_ssids ? sizeof(*tlv) + ssid_len : 0) + - (arg->n_bssids ? sizeof(*tlv) + bssid_len : 0) + - (arg->ie_len ? sizeof(*tlv) + ie_len : 0); + sizeof(*tlv) + chan_len + + sizeof(*tlv) + ssid_len + + sizeof(*tlv) + bssid_len + + sizeof(*tlv) + ie_len; skb = ath10k_wmi_alloc_skb(ar, len); if (!skb) diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index 22cf011e839afc190c55c65a387351787369e37d..e75bba0bbf6746ed50f76b4c4096275d402495cc 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -1228,6 +1228,11 @@ struct wmi_tlv_resource_config { __le32 keep_alive_pattern_size; __le32 max_tdls_concurrent_sleep_sta; __le32 max_tdls_concurrent_buffer_sta; + __le32 wmi_send_separate; + __le32 num_ocb_vdevs; + __le32 num_ocb_channels; + __le32 num_ocb_schedules; + __le32 host_capab; } __packed; struct wmi_tlv_init_cmd { diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 38a97086708b53a6dd6274d0cc70721f77bfec59..2ab5311659ea9446689af6112362df3a85ccd4e0 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1741,8 +1741,8 @@ int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb, cmd_hdr->cmd_id = __cpu_to_le32(cmd); memset(skb_cb, 0, sizeof(*skb_cb)); + trace_ath10k_wmi_cmd(ar, cmd_id, skb->data, skb->len); ret = ath10k_htc_send(&ar->htc, ar->wmi.eid, skb); - trace_ath10k_wmi_cmd(ar, cmd_id, skb->data, skb->len, ret); if (ret) goto err_pull; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index bab876cf25fee02279a4a636b2d9aa430c2efab1..d0e05aa437e36549515016d72a35f2cf2dd14629 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -6002,6 +6002,7 @@ enum wmi_peer_param { WMI_PEER_NSS = 0x5, WMI_PEER_USE_4ADDR = 0x6, WMI_PEER_DEBUG = 0xa, + WMI_PEER_PHYMODE = 0xd, WMI_PEER_DUMMY_VAR = 0xff, /* dummy parameter for STA PS workaround */ }; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 8c5c2dd8fa7f13c4d12ebb98fa354deff212e124..a7f506eb7b366475eac78e0393504b29991063ad 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2915,16 +2915,19 @@ void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan, struct ath_regulatory *reg = ath9k_hw_regulatory(ah); struct ieee80211_channel *channel; int chan_pwr, new_pwr; + u16 ctl = NO_CTL; if (!chan) return; + if (!test) + ctl = ath9k_regd_get_ctl(reg, chan); + channel = chan->chan; chan_pwr = min_t(int, channel->max_power * 2, MAX_RATE_POWER); new_pwr = min_t(int, chan_pwr, reg->power_limit); - ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(reg, chan), + ah->eep_ops->set_txpower(ah, chan, ctl, get_antenna_gain(ah, chan), new_pwr, test); } diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index d8b041f48ca8e17ccb59fe4b099c9814d8e76a7c..fa64c1cc94aedb9ca80d1fbf1e9f78230e530ed7 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -86,7 +86,8 @@ static void ath_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_sta *sta = info->status.status_driver_data[0]; - if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) { + if (info->flags & (IEEE80211_TX_CTL_REQ_TX_STATUS | + IEEE80211_TX_STATUS_EOSP)) { ieee80211_tx_status(hw, skb); return; } diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index cc802b468f5c7932c472edfbd5df1c38a256fb77..cd473c179ce074a9027e99a4c272d8c0ef69c797 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -1852,6 +1852,12 @@ static int _wil_cfg80211_merge_extra_ies(const u8 *ies1, u16 ies1_len, u8 *buf, *dpos; const u8 *spos; + if (!ies1) + ies1_len = 0; + + if (!ies2) + ies2_len = 0; + if (ies1_len == 0 && ies2_len == 0) { *merged_ies = NULL; *merged_len = 0; @@ -1861,7 +1867,8 @@ static int _wil_cfg80211_merge_extra_ies(const u8 *ies1, u16 ies1_len, buf = kmalloc(ies1_len + ies2_len, GFP_KERNEL); if (!buf) return -ENOMEM; - memcpy(buf, ies1, ies1_len); + if (ies1) + memcpy(buf, ies1, ies1_len); dpos = buf + ies1_len; spos = ies2; while (spos + 1 < ies2 + ies2_len) { @@ -1871,7 +1878,8 @@ static int _wil_cfg80211_merge_extra_ies(const u8 *ies1, u16 ies1_len, if (spos + ielen > ies2 + ies2_len) break; if (spos[0] == WLAN_EID_VENDOR_SPECIFIC && - !_wil_cfg80211_find_ie(ies1, ies1_len, spos, ielen)) { + (!ies1 || !_wil_cfg80211_find_ie(ies1, ies1_len, + spos, ielen))) { memcpy(dpos, spos, ielen); dpos += ielen; } diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 852ee04aab8e8e2021098febe5808782695ddf92..84455e9f76733b5042fdc206be3049f3b1893e2f 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -961,6 +961,8 @@ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf, int rc; void *frame; + memset(¶ms, 0, sizeof(params)); + if (!len) return -EINVAL; diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 5d287a8e1b458a8aca674275a55c007df944e4c3..a58fccb39bd09a631284e01a252b4b1ebe7e1187 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -575,10 +575,14 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie) } if (isr & BIT_DMA_EP_MISC_ICR_HALP) { - wil_dbg_irq(wil, "irq_misc: HALP IRQ invoked\n"); - wil6210_mask_halp(wil); isr &= ~BIT_DMA_EP_MISC_ICR_HALP; - complete(&wil->halp.comp); + if (atomic_read(&wil->halp.handle_icr)) { + /* no need to handle HALP ICRs until next vote */ + atomic_set(&wil->halp.handle_icr, 0); + wil_dbg_irq(wil, "irq_misc: HALP IRQ invoked\n"); + wil6210_mask_halp(wil); + complete(&wil->halp.comp); + } } wil->isr_misc = isr; diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index e77366fd8d78061dab8091d3e4f554fedc87b659..070619c5376117f004097e81036b0c263474692f 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -1423,8 +1423,15 @@ static void wil_pre_fw_config(struct wil6210_priv *wil) wil6210_clear_irq(wil); /* CAF_ICR - clear and mask */ /* it is W1C, clear by writing back same value */ - wil_s(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0); - wil_w(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0); + if (wil->hw_version < HW_VER_TALYN_MB) { + wil_s(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, ICR), 0); + wil_w(wil, RGF_CAF_ICR + offsetof(struct RGF_ICR, IMV), ~0); + } else { + wil_s(wil, + RGF_CAF_ICR_TALYN_MB + offsetof(struct RGF_ICR, ICR), 0); + wil_w(wil, RGF_CAF_ICR_TALYN_MB + + offsetof(struct RGF_ICR, IMV), ~0); + } /* clear PAL_UNIT_ICR (potential D0->D3 leftover) * In Talyn-MB host cannot access this register due to * access control, hence PAL_UNIT_ICR is cleared by the FW @@ -1851,6 +1858,8 @@ void wil_halp_vote(struct wil6210_priv *wil) if (++wil->halp.ref_cnt == 1) { reinit_completion(&wil->halp.comp); + /* mark to IRQ context to handle HALP ICR */ + atomic_set(&wil->halp.handle_icr, 1); wil6210_set_halp(wil); rc = wait_for_completion_timeout(&wil->halp.comp, to_jiffies); if (!rc) { diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c index 93fcc55bcd22b77514ed7a6e0a0b76b2b6002aca..3a4194779ddf6371da82b934565bbf6c69eb2c27 100644 --- a/drivers/net/wireless/ath/wil6210/pm.c +++ b/drivers/net/wireless/ath/wil6210/pm.c @@ -93,7 +93,11 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime) if (wmi_only || debug_fw) { wil_dbg_pm(wil, "Deny any suspend - %s mode\n", wmi_only ? "wmi_only" : "debug_fw"); - rc = -EPERM; + rc = -EBUSY; + goto out; + } + if (is_runtime && !wil->platform_ops.suspend) { + rc = -EBUSY; goto out; } diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c index 59d0bc752fd07fc53ec6a0388de3318a90860432..16577b2188c5203e2addf6183021612527bad409 100644 --- a/drivers/net/wireless/ath/wil6210/txrx_edma.c +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c @@ -835,23 +835,24 @@ static int wil_rx_error_check_edma(struct wil6210_priv *wil, wil_dbg_txrx(wil, "L2 RX error, l2_rx_status=0x%x\n", l2_rx_status); /* Due to HW issue, KEY error will trigger a MIC error */ - if (l2_rx_status & WIL_RX_EDMA_ERROR_MIC) { - wil_dbg_txrx(wil, - "L2 MIC/KEY error, dropping packet\n"); + if (l2_rx_status == WIL_RX_EDMA_ERROR_MIC) { + wil_err_ratelimited(wil, + "L2 MIC/KEY error, dropping packet\n"); stats->rx_mic_error++; } - if (l2_rx_status & WIL_RX_EDMA_ERROR_KEY) { - wil_dbg_txrx(wil, "L2 KEY error, dropping packet\n"); + if (l2_rx_status == WIL_RX_EDMA_ERROR_KEY) { + wil_err_ratelimited(wil, + "L2 KEY error, dropping packet\n"); stats->rx_key_error++; } - if (l2_rx_status & WIL_RX_EDMA_ERROR_REPLAY) { - wil_dbg_txrx(wil, - "L2 REPLAY error, dropping packet\n"); + if (l2_rx_status == WIL_RX_EDMA_ERROR_REPLAY) { + wil_err_ratelimited(wil, + "L2 REPLAY error, dropping packet\n"); stats->rx_replay++; } - if (l2_rx_status & WIL_RX_EDMA_ERROR_AMSDU) { - wil_dbg_txrx(wil, - "L2 AMSDU error, dropping packet\n"); + if (l2_rx_status == WIL_RX_EDMA_ERROR_AMSDU) { + wil_err_ratelimited(wil, + "L2 AMSDU error, dropping packet\n"); stats->rx_amsdu_error++; } return -EFAULT; diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index efa8a46a55602733b1b68346cd099ad004505c67..0a512fd60711c6e2f62b99e44d096c6c482b2722 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -324,6 +324,7 @@ struct RGF_ICR { /* MAC timer, usec, for packet lifetime */ #define RGF_MAC_MTRL_COUNTER_0 (0x886aa8) +#define RGF_CAF_ICR_TALYN_MB (0x8893d4) /* struct RGF_ICR */ #define RGF_CAF_ICR (0x88946c) /* struct RGF_ICR */ #define RGF_CAF_OSC_CONTROL (0x88afa4) #define BIT_CAF_OSC_XTAL_EN BIT(0) @@ -794,6 +795,7 @@ struct wil_halp { struct mutex lock; /* protect halp ref_cnt */ unsigned int ref_cnt; struct completion comp; + atomic_t handle_icr; }; struct wil_blob_wrapper { diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index f2c93c2a0645567daa2cd18d73271c7604a4cc8c..41b2e9fb3ad73d2e5727e1001a6d7b08d14537a9 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -3342,7 +3342,7 @@ static void wmi_event_handle(struct wil6210_priv *wil, if (mid == MID_BROADCAST) mid = 0; - if (mid >= wil->max_vifs) { + if (mid >= ARRAY_SIZE(wil->vifs) || mid >= wil->max_vifs) { wil_dbg_wmi(wil, "invalid mid %d, event skipped\n", mid); return; diff --git a/drivers/net/wireless/broadcom/b43/leds.c b/drivers/net/wireless/broadcom/b43/leds.c index cb987c2ecc6bf5295684c11da9604c03ef4d2e32..87131f6632929963506d0258d1bc20c97c09e5b8 100644 --- a/drivers/net/wireless/broadcom/b43/leds.c +++ b/drivers/net/wireless/broadcom/b43/leds.c @@ -131,7 +131,7 @@ static int b43_register_led(struct b43_wldev *dev, struct b43_led *led, led->wl = dev->wl; led->index = led_index; led->activelow = activelow; - strncpy(led->name, name, sizeof(led->name)); + strlcpy(led->name, name, sizeof(led->name)); atomic_set(&led->state, 0); led->led_dev.name = led->name; diff --git a/drivers/net/wireless/broadcom/b43legacy/leds.c b/drivers/net/wireless/broadcom/b43legacy/leds.c index fd4565389c77df59056d239e2bc778164a622496..bc922118b6ac641aa1caa800489f77472542fe60 100644 --- a/drivers/net/wireless/broadcom/b43legacy/leds.c +++ b/drivers/net/wireless/broadcom/b43legacy/leds.c @@ -101,7 +101,7 @@ static int b43legacy_register_led(struct b43legacy_wldev *dev, led->dev = dev; led->index = led_index; led->activelow = activelow; - strncpy(led->name, name, sizeof(led->name)); + strlcpy(led->name, name, sizeof(led->name)); led->led_dev.name = led->name; led->led_dev.default_trigger = default_trigger; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index eccd25febfe6035a89df9e342476b43746afe287..4c28b04ea60536dce86508a9bac3168c51015ab2 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -4245,6 +4245,13 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus) brcmf_dbg(TRACE, "Enter\n"); if (bus) { + /* Stop watchdog task */ + if (bus->watchdog_tsk) { + send_sig(SIGTERM, bus->watchdog_tsk, 1); + kthread_stop(bus->watchdog_tsk); + bus->watchdog_tsk = NULL; + } + /* De-register interrupt handler */ brcmf_sdiod_intr_unregister(bus->sdiodev); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_qmath.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_qmath.c index b9672da24a9d3d8f7b58cbe19cc282281cd271ef..b24bc57ca91b8a61bcbf0e26c12e3c3805e820d4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_qmath.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_qmath.c @@ -213,7 +213,7 @@ static const s16 log_table[] = { 30498, 31267, 32024, - 32768 + 32767 }; #define LOG_TABLE_SIZE 32 /* log_table size */ diff --git a/drivers/net/wireless/cnss2/bus.c b/drivers/net/wireless/cnss2/bus.c index 15a2086b2fb70fb2fbbfa0d7a2a19eed98c53309..471bcfbb452758a39fc8c9afcf8b191cea67ccca 100644 --- a/drivers/net/wireless/cnss2/bus.c +++ b/drivers/net/wireless/cnss2/bus.c @@ -332,3 +332,19 @@ int cnss_bus_call_driver_modem_status(struct cnss_plat_data *plat_priv, return -EINVAL; } } + +int cnss_bus_update_status(struct cnss_plat_data *plat_priv, + enum cnss_driver_status status) +{ + if (!plat_priv) + return -ENODEV; + + switch (plat_priv->bus_type) { + case CNSS_BUS_PCI: + return cnss_pci_update_status(plat_priv->bus_priv, status); + default: + cnss_pr_err("Unsupported bus type: %d\n", + plat_priv->bus_type); + return -EINVAL; + } +} diff --git a/drivers/net/wireless/cnss2/bus.h b/drivers/net/wireless/cnss2/bus.h index 05ab66453ef18ba293594a425f9cb043e0ec90d0..87f634f59d5a20131c3d666c466f20bf54ecedb0 100644 --- a/drivers/net/wireless/cnss2/bus.h +++ b/drivers/net/wireless/cnss2/bus.h @@ -48,5 +48,7 @@ int cnss_bus_register_driver_hdlr(struct cnss_plat_data *plat_priv, void *data); int cnss_bus_unregister_driver_hdlr(struct cnss_plat_data *plat_priv); int cnss_bus_call_driver_modem_status(struct cnss_plat_data *plat_priv, int modem_current_status); +int cnss_bus_update_status(struct cnss_plat_data *plat_priv, + enum cnss_driver_status status); #endif /* _CNSS_BUS_H */ diff --git a/drivers/net/wireless/cnss2/debug.c b/drivers/net/wireless/cnss2/debug.c index 53a46202500fc16c7302130024c9333e4132c217..30e37a08d2911307d08cafb05920414f1e0db1f0 100644 --- a/drivers/net/wireless/cnss2/debug.c +++ b/drivers/net/wireless/cnss2/debug.c @@ -428,6 +428,82 @@ static const struct file_operations cnss_reg_write_debug_fops = { .llseek = seq_lseek, }; +static ssize_t cnss_runtime_pm_debug_write(struct file *fp, + const char __user *user_buf, + size_t count, loff_t *off) +{ + struct cnss_plat_data *plat_priv = + ((struct seq_file *)fp->private_data)->private; + struct cnss_pci_data *pci_priv; + char buf[64]; + char *cmd; + unsigned int len = 0; + int ret = 0; + + if (!plat_priv) + return -ENODEV; + + pci_priv = plat_priv->bus_priv; + if (!pci_priv) + return -ENODEV; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + cmd = buf; + + if (sysfs_streq(cmd, "usage_count")) { + cnss_pci_pm_runtime_show_usage_count(pci_priv); + } else if (sysfs_streq(cmd, "get")) { + ret = cnss_pci_pm_runtime_get(pci_priv); + } else if (sysfs_streq(cmd, "get_noresume")) { + cnss_pci_pm_runtime_get_noresume(pci_priv); + } else if (sysfs_streq(cmd, "put_autosuspend")) { + ret = cnss_pci_pm_runtime_put_autosuspend(pci_priv); + } else if (sysfs_streq(cmd, "put_noidle")) { + cnss_pci_pm_runtime_put_noidle(pci_priv); + } else if (sysfs_streq(cmd, "mark_last_busy")) { + cnss_pci_pm_runtime_mark_last_busy(pci_priv); + } else { + cnss_pr_err("Runtime PM debugfs command is invalid\n"); + ret = -EINVAL; + } + + if (ret) + return ret; + + return count; +} + +static int cnss_runtime_pm_debug_show(struct seq_file *s, void *data) +{ + seq_puts(s, "\nUsage: echo > /cnss/runtime_pm\n"); + seq_puts(s, " can be one of below:\n"); + seq_puts(s, "usage_count: get runtime PM usage count\n"); + seq_puts(s, "get: do runtime PM get\n"); + seq_puts(s, "get_noresume: do runtime PM get noresume\n"); + seq_puts(s, "put_noidle: do runtime PM put noidle\n"); + seq_puts(s, "put_autosuspend: do runtime PM put autosuspend\n"); + seq_puts(s, "mark_last_busy: do runtime PM mark last busy\n"); + + return 0; +} + +static int cnss_runtime_pm_debug_open(struct inode *inode, struct file *file) +{ + return single_open(file, cnss_runtime_pm_debug_show, inode->i_private); +} + +static const struct file_operations cnss_runtime_pm_debug_fops = { + .read = seq_read, + .write = cnss_runtime_pm_debug_write, + .open = cnss_runtime_pm_debug_open, + .owner = THIS_MODULE, + .llseek = seq_lseek, +}; + #ifdef CONFIG_CNSS2_DEBUG static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv) { @@ -439,6 +515,8 @@ static int cnss_create_debug_only_node(struct cnss_plat_data *plat_priv) &cnss_reg_read_debug_fops); debugfs_create_file("reg_write", 0600, root_dentry, plat_priv, &cnss_reg_write_debug_fops); + debugfs_create_file("runtime_pm", 0600, root_dentry, plat_priv, + &cnss_runtime_pm_debug_fops); return 0; } diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c index 44c48c503f06d5877565f77e1d120baf0498a3a2..3dbb04325d579053c7452d367312e069cffde037 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -426,6 +426,7 @@ static int cnss_fw_ready_hdlr(struct cnss_plat_data *plat_priv) del_timer(&plat_priv->fw_boot_timer); set_bit(CNSS_FW_READY, &plat_priv->driver_state); + clear_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state); if (test_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state)) { clear_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state); @@ -901,7 +902,6 @@ static int cnss_do_recovery(struct cnss_plat_data *plat_priv, break; case CNSS_REASON_RDDM: cnss_bus_collect_dump_info(plat_priv, false); - clear_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state); break; case CNSS_REASON_DEFAULT: case CNSS_REASON_TIMEOUT: @@ -994,6 +994,8 @@ void cnss_schedule_recovery(struct device *dev, struct cnss_recovery_data *data; int gfp = GFP_KERNEL; + cnss_bus_update_status(plat_priv, CNSS_FW_DOWN); + if (in_interrupt() || irqs_disabled()) gfp = GFP_ATOMIC; @@ -1039,19 +1041,34 @@ static int cnss_cold_boot_cal_start_hdlr(struct cnss_plat_data *plat_priv) { int ret = 0; + if (test_bit(CNSS_FW_READY, &plat_priv->driver_state) || + test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) || + test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) { + cnss_pr_dbg("Device is already active, ignore calibration\n"); + goto out; + } + set_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state); + reinit_completion(&plat_priv->cal_complete); ret = cnss_bus_dev_powerup(plat_priv); - if (ret) + if (ret) { + complete(&plat_priv->cal_complete); clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state); + } +out: return ret; } static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv) { + if (!test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state)) + return 0; + plat_priv->cal_done = true; cnss_wlfw_wlan_mode_send_sync(plat_priv, CNSS_OFF); cnss_bus_dev_shutdown(plat_priv); + complete(&plat_priv->cal_complete); clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state); return 0; @@ -1533,6 +1550,36 @@ static void cnss_event_work_deinit(struct cnss_plat_data *plat_priv) destroy_workqueue(plat_priv->event_wq); } +static int cnss_misc_init(struct cnss_plat_data *plat_priv) +{ + int ret; + + setup_timer(&plat_priv->fw_boot_timer, cnss_bus_fw_boot_timeout_hdlr, + (unsigned long)plat_priv); + + register_pm_notifier(&cnss_pm_notifier); + + ret = device_init_wakeup(&plat_priv->plat_dev->dev, true); + if (ret) + cnss_pr_err("Failed to init platform device wakeup source, err = %d\n", + ret); + + init_completion(&plat_priv->power_up_complete); + init_completion(&plat_priv->cal_complete); + mutex_init(&plat_priv->dev_lock); + + return 0; +} + +static void cnss_misc_deinit(struct cnss_plat_data *plat_priv) +{ + complete_all(&plat_priv->cal_complete); + complete_all(&plat_priv->power_up_complete); + device_init_wakeup(&plat_priv->plat_dev->dev, false); + unregister_pm_notifier(&cnss_pm_notifier); + del_timer(&plat_priv->fw_boot_timer); +} + static const struct platform_device_id cnss_platform_id_table[] = { { .name = "qca6174", .driver_data = QCA6174_DEVICE_ID, }, { .name = "qca6290", .driver_data = QCA6290_DEVICE_ID, }, @@ -1626,23 +1673,16 @@ static int cnss_probe(struct platform_device *plat_dev) if (ret) goto deinit_qmi; - setup_timer(&plat_priv->fw_boot_timer, cnss_bus_fw_boot_timeout_hdlr, - (unsigned long)plat_priv); - - register_pm_notifier(&cnss_pm_notifier); - - ret = device_init_wakeup(&plat_dev->dev, true); + ret = cnss_misc_init(plat_priv); if (ret) - cnss_pr_err("Failed to init platform device wakeup source, err = %d\n", - ret); - - init_completion(&plat_priv->power_up_complete); - mutex_init(&plat_priv->dev_lock); + goto destroy_debugfs; cnss_pr_info("Platform driver probed successfully.\n"); return 0; +destroy_debugfs: + cnss_debugfs_destroy(plat_priv); deinit_qmi: cnss_qmi_deinit(plat_priv); deinit_event_work: @@ -1672,10 +1712,7 @@ static int cnss_remove(struct platform_device *plat_dev) { struct cnss_plat_data *plat_priv = platform_get_drvdata(plat_dev); - complete_all(&plat_priv->power_up_complete); - device_init_wakeup(&plat_dev->dev, false); - unregister_pm_notifier(&cnss_pm_notifier); - del_timer(&plat_priv->fw_boot_timer); + cnss_misc_deinit(plat_priv); cnss_debugfs_destroy(plat_priv); cnss_qmi_deinit(plat_priv); cnss_event_work_deinit(plat_priv); diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h index 00ab8a49a7b2854ec3c9fce5eb3f9336b69db0d8..0814cdfbfa96116c67af3a7c19a66da9381cf907 100644 --- a/drivers/net/wireless/cnss2/main.h +++ b/drivers/net/wireless/cnss2/main.h @@ -241,6 +241,7 @@ struct cnss_plat_data { atomic_t pm_count; struct timer_list fw_boot_timer; struct completion power_up_complete; + struct completion cal_complete; struct mutex dev_lock; /* mutex for register access through debugfs */ u32 diag_reg_read_addr; u32 diag_reg_read_mem_type; diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index 7d80e5b90b79b86b841c467957dec419980d4a75..3ad711457628bb6dd141d41d4021c083aaaad620 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -371,6 +371,25 @@ int cnss_pci_call_driver_modem_status(struct cnss_pci_data *pci_priv, return 0; } +int cnss_pci_update_status(struct cnss_pci_data *pci_priv, + enum cnss_driver_status status) +{ + struct cnss_wlan_driver *driver_ops; + + if (!pci_priv) + return -ENODEV; + + driver_ops = pci_priv->driver_ops; + if (!driver_ops || !driver_ops->update_status) + return -EINVAL; + + cnss_pr_dbg("Update driver status: %d\n", status); + + driver_ops->update_status(pci_priv->pci_dev, status); + + return 0; +} + static int cnss_qca6174_powerup(struct cnss_pci_data *pci_priv) { int ret = 0; @@ -706,6 +725,7 @@ int cnss_wlan_register_driver(struct cnss_wlan_driver *driver_ops) int ret = 0; struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL); struct cnss_pci_data *pci_priv; + unsigned int timeout; if (!plat_priv) { cnss_pr_err("plat_priv is NULL\n"); @@ -723,10 +743,27 @@ int cnss_wlan_register_driver(struct cnss_wlan_driver *driver_ops) return -EEXIST; } + if (!test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state)) + goto register_driver; + + cnss_pr_dbg("Start to wait for calibration to complete\n"); + + timeout = cnss_get_boot_timeout(&pci_priv->pci_dev->dev); + ret = wait_for_completion_timeout(&plat_priv->cal_complete, + msecs_to_jiffies(timeout) << 2); + if (!ret) { + cnss_pr_err("Timeout waiting for calibration to complete\n"); + ret = -EAGAIN; + goto out; + } + +register_driver: ret = cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_REGISTER_DRIVER, CNSS_EVENT_SYNC_UNINTERRUPTIBLE, driver_ops); + +out: return ret; } EXPORT_SYMBOL(cnss_wlan_register_driver); @@ -1154,6 +1191,59 @@ int cnss_wlan_pm_control(struct device *dev, bool vote) } EXPORT_SYMBOL(cnss_wlan_pm_control); +void cnss_pci_pm_runtime_show_usage_count(struct cnss_pci_data *pci_priv) +{ + struct device *dev; + + if (!pci_priv) + return; + + dev = &pci_priv->pci_dev->dev; + + cnss_pr_dbg("Runtime PM usage count: %d\n", + atomic_read(&dev->power.usage_count)); +} + +int cnss_pci_pm_runtime_get(struct cnss_pci_data *pci_priv) +{ + if (!pci_priv) + return -ENODEV; + + return pm_runtime_get(&pci_priv->pci_dev->dev); +} + +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); +} + +int cnss_pci_pm_runtime_put_autosuspend(struct cnss_pci_data *pci_priv) +{ + if (!pci_priv) + return -ENODEV; + + return pm_runtime_put_autosuspend(&pci_priv->pci_dev->dev); +} + +void cnss_pci_pm_runtime_put_noidle(struct cnss_pci_data *pci_priv) +{ + if (!pci_priv) + return; + + pm_runtime_put_noidle(&pci_priv->pci_dev->dev); +} + +void cnss_pci_pm_runtime_mark_last_busy(struct cnss_pci_data *pci_priv) +{ + if (!pci_priv) + return; + + pm_runtime_mark_last_busy(&pci_priv->pci_dev->dev); +} + int cnss_auto_suspend(struct device *dev) { int ret = 0; @@ -1954,10 +2044,6 @@ static void cnss_mhi_notify_status(struct mhi_controller *mhi_ctrl, void *priv, return; } - if (pci_priv->driver_ops && pci_priv->driver_ops->update_status) - pci_priv->driver_ops->update_status(pci_priv->pci_dev, - CNSS_FW_DOWN); - switch (reason) { case MHI_CB_EE_RDDM: cnss_reason = CNSS_REASON_RDDM; @@ -1970,8 +2056,7 @@ static void cnss_mhi_notify_status(struct mhi_controller *mhi_ctrl, void *priv, set_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state); del_timer(&plat_priv->fw_boot_timer); - cnss_schedule_recovery(&pci_priv->pci_dev->dev, - cnss_reason); + cnss_schedule_recovery(&pci_priv->pci_dev->dev, cnss_reason); } static int cnss_pci_get_mhi_msi(struct cnss_pci_data *pci_priv) diff --git a/drivers/net/wireless/cnss2/pci.h b/drivers/net/wireless/cnss2/pci.h index c8de4d74a1875646d2a4a227a5283e7c4fcee79b..6476ce120f994b8706b76ca1917c78d9e8996d5d 100644 --- a/drivers/net/wireless/cnss2/pci.h +++ b/drivers/net/wireless/cnss2/pci.h @@ -143,5 +143,13 @@ int cnss_pci_register_driver_hdlr(struct cnss_pci_data *pci_priv, void *data); int cnss_pci_unregister_driver_hdlr(struct cnss_pci_data *pci_priv); int cnss_pci_call_driver_modem_status(struct cnss_pci_data *pci_priv, int modem_current_status); +void cnss_pci_pm_runtime_show_usage_count(struct cnss_pci_data *pci_priv); +int cnss_pci_pm_runtime_get(struct cnss_pci_data *pci_priv); +void cnss_pci_pm_runtime_get_noresume(struct cnss_pci_data *pci_priv); +int cnss_pci_pm_runtime_put_autosuspend(struct cnss_pci_data *pci_priv); +void cnss_pci_pm_runtime_put_noidle(struct cnss_pci_data *pci_priv); +void cnss_pci_pm_runtime_mark_last_busy(struct cnss_pci_data *pci_priv); +int cnss_pci_update_status(struct cnss_pci_data *pci_priv, + enum cnss_driver_status status); #endif /* _CNSS_PCI_H */ diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c index 6a38b66cbb38854e0ba59ed6d6e30c71d4003f71..5f948a4c0abe3d6ea1f81b551ac839e6fe9cafd5 100644 --- a/drivers/net/wireless/cnss2/qmi.c +++ b/drivers/net/wireless/cnss2/qmi.c @@ -47,7 +47,7 @@ MODULE_PARM_DESC(qmi_timeout, "Timeout for QMI message in milliseconds"); #define QMI_WLFW_MAX_RECV_BUF_SIZE SZ_8K -static bool daemon_support; +static bool daemon_support = true; module_param(daemon_support, bool, 0600); MODULE_PARM_DESC(daemon_support, "User space has cnss-daemon support or not"); @@ -113,6 +113,8 @@ static int cnss_wlfw_ind_register_send_sync(struct cnss_plat_data *plat_priv) req->fw_init_done_enable = 1; req->pin_connect_result_enable_valid = 1; req->pin_connect_result_enable = 1; + req->cal_done_enable_valid = 1; + req->cal_done_enable = 1; ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, wlfw_ind_register_resp_msg_v01_ei, resp); @@ -1185,6 +1187,24 @@ static void cnss_wlfw_pin_result_ind_cb(struct qmi_handle *qmi_wlfw, ind_msg->rf_pin_result); } +static void cnss_wlfw_cal_done_ind_cb(struct qmi_handle *qmi_wlfw, + struct sockaddr_qrtr *sq, + struct qmi_txn *txn, const void *data) +{ + struct cnss_plat_data *plat_priv = + container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw); + + cnss_pr_dbg("Received QMI WLFW calibration done indication\n"); + + if (!txn) { + cnss_pr_err("Spurious indication\n"); + return; + } + + cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE, + 0, NULL); +} + static struct qmi_msg_handler qmi_wlfw_msg_handlers[] = { { .type = QMI_INDICATION, @@ -1222,6 +1242,13 @@ static struct qmi_msg_handler qmi_wlfw_msg_handlers[] = { sizeof(struct wlfw_pin_connect_result_ind_msg_v01), .fn = cnss_wlfw_pin_result_ind_cb }, + { + .type = QMI_INDICATION, + .msg_id = QMI_WLFW_CAL_DONE_IND_V01, + .ei = wlfw_cal_done_ind_msg_v01_ei, + .decoded_size = sizeof(struct wlfw_cal_done_ind_msg_v01), + .fn = cnss_wlfw_cal_done_ind_cb + }, {} }; diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index d686ba10fecc1804bb00db48dcfc1c96eda1165f..aafa7aa18fbd7903d5fe689ddb6dba08865f5164 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2632,9 +2632,6 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, IEEE80211_VHT_CAP_SHORT_GI_80 | IEEE80211_VHT_CAP_SHORT_GI_160 | IEEE80211_VHT_CAP_TXSTBC | - IEEE80211_VHT_CAP_RXSTBC_1 | - IEEE80211_VHT_CAP_RXSTBC_2 | - IEEE80211_VHT_CAP_RXSTBC_3 | IEEE80211_VHT_CAP_RXSTBC_4 | IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK; sband->vht_cap.vht_mcs.rx_mcs_map = @@ -3124,6 +3121,11 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info) if (info->attrs[HWSIM_ATTR_CHANNELS]) param.channels = nla_get_u32(info->attrs[HWSIM_ATTR_CHANNELS]); + if (param.channels < 1) { + GENL_SET_ERR_MSG(info, "must have at least one channel"); + return -EINVAL; + } + if (param.channels > CFG80211_MAX_NUM_DIFFERENT_CHANNELS) { GENL_SET_ERR_MSG(info, "too many channels specified"); return -EINVAL; diff --git a/drivers/net/wireless/marvell/libertas/dev.h b/drivers/net/wireless/marvell/libertas/dev.h index dd1ee1f0af48968046c4ca605e90ae53754fba89..469134930026520bd6253ecee125af5cccee19b3 100644 --- a/drivers/net/wireless/marvell/libertas/dev.h +++ b/drivers/net/wireless/marvell/libertas/dev.h @@ -104,6 +104,7 @@ struct lbs_private { u8 fw_ready; u8 surpriseremoved; u8 setup_fw_on_resume; + u8 power_up_on_resume; int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb); void (*reset_card) (struct lbs_private *priv); int (*power_save) (struct lbs_private *priv); diff --git a/drivers/net/wireless/marvell/libertas/if_sdio.c b/drivers/net/wireless/marvell/libertas/if_sdio.c index 2300e796c6ab9e8106e132b3988fa240dc4783a4..43743c26c071f538f1942696aa97d20b0cbf091d 100644 --- a/drivers/net/wireless/marvell/libertas/if_sdio.c +++ b/drivers/net/wireless/marvell/libertas/if_sdio.c @@ -1290,15 +1290,23 @@ static void if_sdio_remove(struct sdio_func *func) static int if_sdio_suspend(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); - int ret; struct if_sdio_card *card = sdio_get_drvdata(func); + struct lbs_private *priv = card->priv; + int ret; mmc_pm_flag_t flags = sdio_get_host_pm_caps(func); + priv->power_up_on_resume = false; /* If we're powered off anyway, just let the mmc layer remove the * card. */ - if (!lbs_iface_active(card->priv)) - return -ENOSYS; + if (!lbs_iface_active(priv)) { + if (priv->fw_ready) { + priv->power_up_on_resume = true; + if_sdio_power_off(card); + } + + return 0; + } dev_info(dev, "%s: suspend: PM flags = 0x%x\n", sdio_func_id(func), flags); @@ -1306,9 +1314,14 @@ static int if_sdio_suspend(struct device *dev) /* If we aren't being asked to wake on anything, we should bail out * and let the SD stack power down the card. */ - if (card->priv->wol_criteria == EHS_REMOVE_WAKEUP) { + if (priv->wol_criteria == EHS_REMOVE_WAKEUP) { dev_info(dev, "Suspend without wake params -- powering down card\n"); - return -ENOSYS; + if (priv->fw_ready) { + priv->power_up_on_resume = true; + if_sdio_power_off(card); + } + + return 0; } if (!(flags & MMC_PM_KEEP_POWER)) { @@ -1321,7 +1334,7 @@ static int if_sdio_suspend(struct device *dev) if (ret) return ret; - ret = lbs_suspend(card->priv); + ret = lbs_suspend(priv); if (ret) return ret; @@ -1336,6 +1349,11 @@ static int if_sdio_resume(struct device *dev) dev_info(dev, "%s: resume: we're back\n", sdio_func_id(func)); + if (card->priv->power_up_on_resume) { + if_sdio_power_on(card); + wait_event(card->pwron_waitq, card->priv->fw_ready); + } + ret = lbs_resume(card->priv); return ret; diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 9935bd09db1fb309090222be94c85ec98917b5cc..d4947e3a909ec6758a7554647f18125d3c6cebbf 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2928,6 +2928,8 @@ static void rndis_wlan_auth_indication(struct usbnet *usbdev, while (buflen >= sizeof(*auth_req)) { auth_req = (void *)buf; + if (buflen < le32_to_cpu(auth_req->length)) + return; type = "unknown"; flags = le32_to_cpu(auth_req->flags); pairwise_error = false; diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 761cf8573a805e272121fa05bf129f1ee600a10a..f48c3f62966d43f0f74c83f311958f89da62f3dc 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -35,6 +35,7 @@ #include "wl12xx_80211.h" #include "cmd.h" #include "event.h" +#include "ps.h" #include "tx.h" #include "hw_ops.h" @@ -191,6 +192,10 @@ int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl, timeout_time = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT); + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + return ret; + do { if (time_after(jiffies, timeout_time)) { wl1271_debug(DEBUG_CMD, "timeout waiting for event %d", @@ -222,6 +227,7 @@ int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl, } while (!event); out: + wl1271_ps_elp_sleep(wl); kfree(events_vector); return ret; } diff --git a/drivers/net/wireless/ti/wlcore/rx.c b/drivers/net/wireless/ti/wlcore/rx.c index 0f15696195f884f59c82e431757593362a0489ca..078a4940bc5c3bcd9a496b8afec6536c61fee5c8 100644 --- a/drivers/net/wireless/ti/wlcore/rx.c +++ b/drivers/net/wireless/ti/wlcore/rx.c @@ -59,7 +59,7 @@ static u32 wlcore_rx_get_align_buf_size(struct wl1271 *wl, u32 pkt_len) static void wl1271_rx_status(struct wl1271 *wl, struct wl1271_rx_descriptor *desc, struct ieee80211_rx_status *status, - u8 beacon) + u8 beacon, u8 probe_rsp) { memset(status, 0, sizeof(struct ieee80211_rx_status)); @@ -106,6 +106,9 @@ static void wl1271_rx_status(struct wl1271 *wl, } } + if (beacon || probe_rsp) + status->boottime_ns = ktime_get_boot_ns(); + if (beacon) wlcore_set_pending_regdomain_ch(wl, (u16)desc->channel, status->band); @@ -191,7 +194,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, if (ieee80211_is_data_present(hdr->frame_control)) is_data = 1; - wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); + wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon, + ieee80211_is_probe_resp(hdr->frame_control)); wlcore_hw_set_rx_csum(wl, desc, skb); seq_num = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; diff --git a/drivers/net/xen-netback/hash.c b/drivers/net/xen-netback/hash.c index 3c4c58b9fe76edfbf3d27fb5b6dbd0184ba706c0..3b6fb5b3bdb23ce6ab65b9947ba95cecbd8b59b1 100644 --- a/drivers/net/xen-netback/hash.c +++ b/drivers/net/xen-netback/hash.c @@ -332,20 +332,22 @@ u32 xenvif_set_hash_mapping_size(struct xenvif *vif, u32 size) u32 xenvif_set_hash_mapping(struct xenvif *vif, u32 gref, u32 len, u32 off) { - u32 *mapping = &vif->hash.mapping[off]; + u32 *mapping = vif->hash.mapping; struct gnttab_copy copy_op = { .source.u.ref = gref, .source.domid = vif->domid, - .dest.u.gmfn = virt_to_gfn(mapping), .dest.domid = DOMID_SELF, - .dest.offset = xen_offset_in_page(mapping), - .len = len * sizeof(u32), + .len = len * sizeof(*mapping), .flags = GNTCOPY_source_gref }; - if ((off + len > vif->hash.size) || copy_op.len > XEN_PAGE_SIZE) + if ((off + len < off) || (off + len > vif->hash.size) || + len > XEN_PAGE_SIZE / sizeof(*mapping)) return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER; + copy_op.dest.u.gmfn = virt_to_gfn(mapping + off); + copy_op.dest.offset = xen_offset_in_page(mapping + off); + while (len-- != 0) if (mapping[off++] >= vif->num_queues) return XEN_NETIF_CTRL_STATUS_INVALID_PARAMETER; diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index dfc076f9ee4b582ada02f5a946fcef18ae91d2ad..1a40fc3517a8f0b6d443c5e16c94b18c700a4847 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -87,8 +87,7 @@ struct netfront_cb { /* IRQ name is queue name with "-tx" or "-rx" appended */ #define IRQ_NAME_SIZE (QUEUE_NAME_SIZE + 3) -static DECLARE_WAIT_QUEUE_HEAD(module_load_q); -static DECLARE_WAIT_QUEUE_HEAD(module_unload_q); +static DECLARE_WAIT_QUEUE_HEAD(module_wq); struct netfront_stats { u64 packets; @@ -894,7 +893,6 @@ static RING_IDX xennet_fill_frags(struct netfront_queue *queue, struct sk_buff *skb, struct sk_buff_head *list) { - struct skb_shared_info *shinfo = skb_shinfo(skb); RING_IDX cons = queue->rx.rsp_cons; struct sk_buff *nskb; @@ -903,15 +901,20 @@ static RING_IDX xennet_fill_frags(struct netfront_queue *queue, RING_GET_RESPONSE(&queue->rx, ++cons); skb_frag_t *nfrag = &skb_shinfo(nskb)->frags[0]; - if (shinfo->nr_frags == MAX_SKB_FRAGS) { + if (skb_shinfo(skb)->nr_frags == MAX_SKB_FRAGS) { unsigned int pull_to = NETFRONT_SKB_CB(skb)->pull_to; BUG_ON(pull_to <= skb_headlen(skb)); __pskb_pull_tail(skb, pull_to - skb_headlen(skb)); } - BUG_ON(shinfo->nr_frags >= MAX_SKB_FRAGS); + if (unlikely(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS)) { + queue->rx.rsp_cons = ++cons; + kfree_skb(nskb); + return ~0U; + } - skb_add_rx_frag(skb, shinfo->nr_frags, skb_frag_page(nfrag), + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, + skb_frag_page(nfrag), rx->offset, rx->status, PAGE_SIZE); skb_shinfo(nskb)->nr_frags = 0; @@ -1045,6 +1048,8 @@ static int xennet_poll(struct napi_struct *napi, int budget) skb->len += rx->status; i = xennet_fill_frags(queue, skb, &tmpq); + if (unlikely(i == ~0U)) + goto err; if (rx->flags & XEN_NETRXF_csum_blank) skb->ip_summed = CHECKSUM_PARTIAL; @@ -1331,11 +1336,11 @@ static struct net_device *xennet_create_dev(struct xenbus_device *dev) netif_carrier_off(netdev); xenbus_switch_state(dev, XenbusStateInitialising); - wait_event(module_load_q, - xenbus_read_driver_state(dev->otherend) != - XenbusStateClosed && - xenbus_read_driver_state(dev->otherend) != - XenbusStateUnknown); + wait_event(module_wq, + xenbus_read_driver_state(dev->otherend) != + XenbusStateClosed && + xenbus_read_driver_state(dev->otherend) != + XenbusStateUnknown); return netdev; exit: @@ -1603,6 +1608,7 @@ static int xennet_init_queue(struct netfront_queue *queue) { unsigned short i; int err = 0; + char *devid; spin_lock_init(&queue->tx_lock); spin_lock_init(&queue->rx_lock); @@ -1610,8 +1616,9 @@ static int xennet_init_queue(struct netfront_queue *queue) setup_timer(&queue->rx_refill_timer, rx_refill_timeout, (unsigned long)queue); - snprintf(queue->name, sizeof(queue->name), "%s-q%u", - queue->info->netdev->name, queue->id); + devid = strrchr(queue->info->xbdev->nodename, '/') + 1; + snprintf(queue->name, sizeof(queue->name), "vif%s-q%u", + devid, queue->id); /* Initialise tx_skbs as a free chain containing every entry. */ queue->tx_skb_freelist = 0; @@ -2007,15 +2014,14 @@ static void netback_changed(struct xenbus_device *dev, dev_dbg(&dev->dev, "%s\n", xenbus_strstate(backend_state)); + wake_up_all(&module_wq); + switch (backend_state) { case XenbusStateInitialising: case XenbusStateInitialised: case XenbusStateReconfiguring: case XenbusStateReconfigured: - break; - case XenbusStateUnknown: - wake_up_all(&module_unload_q); break; case XenbusStateInitWait: @@ -2031,12 +2037,10 @@ static void netback_changed(struct xenbus_device *dev, break; case XenbusStateClosed: - wake_up_all(&module_unload_q); if (dev->state == XenbusStateClosed) break; /* Missed the backend's CLOSING state -- fallthrough */ case XenbusStateClosing: - wake_up_all(&module_unload_q); xenbus_frontend_closed(dev); break; } @@ -2144,14 +2148,14 @@ static int xennet_remove(struct xenbus_device *dev) if (xenbus_read_driver_state(dev->otherend) != XenbusStateClosed) { xenbus_switch_state(dev, XenbusStateClosing); - wait_event(module_unload_q, + wait_event(module_wq, xenbus_read_driver_state(dev->otherend) == XenbusStateClosing || xenbus_read_driver_state(dev->otherend) == XenbusStateUnknown); xenbus_switch_state(dev, XenbusStateClosed); - wait_event(module_unload_q, + wait_event(module_wq, xenbus_read_driver_state(dev->otherend) == XenbusStateClosed || xenbus_read_driver_state(dev->otherend) == diff --git a/drivers/nfc/nq-nci.c b/drivers/nfc/nq-nci.c index 9d5d6758dca988a7cb234342f1f5aa7ddbdddffb..320998fc4d0c42d2f0e27376134c9c2dead69b5b 100644 --- a/drivers/nfc/nq-nci.c +++ b/drivers/nfc/nq-nci.c @@ -548,15 +548,28 @@ int nfc_ioctl_power_states(struct file *filp, unsigned long arg) } else if (arg == 4) { /* * Setting firmware download gpio to HIGH for SN100U - * FW download usecase + * before FW download start */ - dev_dbg(&nqx_dev->client->dev, "SN100 fw gpio control block\n"); + dev_dbg(&nqx_dev->client->dev, "SN100 fw gpio HIGH\n"); if (gpio_is_valid(nqx_dev->firm_gpio)) { gpio_set_value(nqx_dev->firm_gpio, 1); usleep_range(10000, 10100); } else dev_err(&nqx_dev->client->dev, "firm_gpio is invalid\n"); + } else if (arg == 6) { + /* + * Setting firmware download gpio to LOW for SN100U + * FW download finished + */ + dev_dbg(&nqx_dev->client->dev, "SN100 fw gpio LOW\n"); + if (gpio_is_valid(nqx_dev->firm_gpio)) { + gpio_set_value(nqx_dev->firm_gpio, 0); + usleep_range(10000, 10100); + } else { + dev_err(&nqx_dev->client->dev, + "firm_gpio is invalid\n"); + } } else { r = -ENOIOCTLCMD; } @@ -676,6 +689,7 @@ static int nfcc_hw_check(struct i2c_client *client, struct nqx_dev *nqx_dev) { int ret = 0; + int gpio_retry_count = 0; unsigned char init_rsp_len = 0; unsigned int enable_gpio = nqx_dev->en_gpio; char *nci_reset_cmd = NULL; @@ -707,6 +721,7 @@ static int nfcc_hw_check(struct i2c_client *client, struct nqx_dev *nqx_dev) goto done; } +reset_enable_gpio: /* making sure that the NFCC starts in a clean state. */ gpio_set_value(enable_gpio, 0);/* ULPM: Disable */ /* hardware dependent delay */ @@ -734,6 +749,9 @@ static int nfcc_hw_check(struct i2c_client *client, struct nqx_dev *nqx_dev) if (ret < 0) { dev_err(&client->dev, "%s: - i2c_master_recv Error\n", __func__); + gpio_retry_count = gpio_retry_count + 1; + if (gpio_retry_count < MAX_RETRY_COUNT) + goto reset_enable_gpio; goto err_nfcc_hw_check; } nci_init_cmd[0] = 0x20; diff --git a/drivers/nfc/pn533/usb.c b/drivers/nfc/pn533/usb.c index d5553c47014fade81a4f461903b3cb6c4372ccf5..5d823e965883b0f5f23db5ab39afc9f96a128267 100644 --- a/drivers/nfc/pn533/usb.c +++ b/drivers/nfc/pn533/usb.c @@ -74,7 +74,7 @@ static void pn533_recv_response(struct urb *urb) struct sk_buff *skb = NULL; if (!urb->status) { - skb = alloc_skb(urb->actual_length, GFP_KERNEL); + skb = alloc_skb(urb->actual_length, GFP_ATOMIC); if (!skb) { nfc_err(&phy->udev->dev, "failed to alloc memory\n"); } else { @@ -186,7 +186,7 @@ static int pn533_usb_send_frame(struct pn533 *dev, if (dev->protocol_type == PN533_PROTO_REQ_RESP) { /* request for response for sent packet directly */ - rc = pn533_submit_urb_for_response(phy, GFP_ATOMIC); + rc = pn533_submit_urb_for_response(phy, GFP_KERNEL); if (rc) goto error; } else if (dev->protocol_type == PN533_PROTO_REQ_ACK_RESP) { diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index 2fffd42767c7b5ddb398b32c3d5a1ec7e8e1dcc8..fb5ab5812a22f255cfe8766ee3a82cea7dd375bb 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c @@ -808,9 +808,9 @@ u32 nd_cmd_out_size(struct nvdimm *nvdimm, int cmd, * overshoots the remainder by 4 bytes, assume it was * including 'status'. */ - if (out_field[1] - 8 == remainder) + if (out_field[1] - 4 == remainder) return remainder; - return out_field[1] - 4; + return out_field[1] - 8; } else if (cmd == ND_CMD_CALL) { struct nd_cmd_pkg *pkg = (struct nd_cmd_pkg *) in_field; diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 38c128f230e7cdf1221e90c4f878f695347a077e..3a63d58d2ca9f86f6d6f39a6b0516ce1fa44116a 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -1016,7 +1016,7 @@ static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns, status = nvme_submit_user_cmd(ns ? ns->queue : ctrl->admin_q, &c, (void __user *)(uintptr_t)cmd.addr, cmd.data_len, - (void __user *)(uintptr_t)cmd.metadata, cmd.metadata, + (void __user *)(uintptr_t)cmd.metadata, cmd.metadata_len, 0, &cmd.result, timeout); if (status >= 0) { if (put_user(cmd.result, &ucmd->result)) diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index 7deb7b5d868374667cb58a2e2db697caf3b130e8..058d542647dd5d1f6b8ba55b166c3a4cf03f89a4 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -2868,6 +2868,10 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts, } if (ret) { + nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_DELETING); + cancel_work_sync(&ctrl->ctrl.reset_work); + cancel_delayed_work_sync(&ctrl->connect_work); + /* couldn't schedule retry - fail out */ dev_err(ctrl->ctrl.device, "NVME-FC{%d}: Connect retry failed\n", ctrl->cnum); diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index a67d037165104db83dea64ab0bf99f05ee64e8db..afb99876fa9e1ad5be351d602e1fc1358bc81340 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -306,6 +306,14 @@ static bool nvme_dbbuf_update_and_check_event(u16 value, u32 *dbbuf_db, old_value = *dbbuf_db; *dbbuf_db = value; + /* + * Ensure that the doorbell is updated before reading the event + * index from memory. The controller needs to provide similar + * ordering to ensure the envent index is updated before reading + * the doorbell. + */ + mb(); + if (!nvme_dbbuf_need_event(*dbbuf_ei, value, old_value)) return false; } diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index 48a831d58e7aeab2f628bb43cc9c84339f6bb5a2..9fffe41ead5009c497d65ce16bcf67da31bd41ea 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -1728,6 +1728,8 @@ static void nvme_rdma_shutdown_ctrl(struct nvme_rdma_ctrl *ctrl, bool shutdown) nvme_stop_queues(&ctrl->ctrl); blk_mq_tagset_busy_iter(&ctrl->tag_set, nvme_cancel_request, &ctrl->ctrl); + if (shutdown) + nvme_start_queues(&ctrl->ctrl); nvme_rdma_destroy_io_queues(ctrl, shutdown); } diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index 240b0d628222026966db95be698c37031fb0c2c3..5fa7856f6b344c1d5dbef76b6d72a9ca1aa88513 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -598,6 +598,14 @@ static void nvmet_start_ctrl(struct nvmet_ctrl *ctrl) } ctrl->csts = NVME_CSTS_RDY; + + /* + * Controllers that are not yet enabled should not really enforce the + * keep alive timeout, but we still want to track a timeout and cleanup + * in case a host died before it enabled the controller. Hence, simply + * reset the keep alive timer when the controller is enabled. + */ + mod_delayed_work(system_wq, &ctrl->ka_work, ctrl->kato * HZ); } static void nvmet_clear_ctrl(struct nvmet_ctrl *ctrl) diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c index c0080f6ab2f5b209eb8aeae003df6659f9124f11..0b0a4825b3eb1274a776eafc502de4787ffa8b11 100644 --- a/drivers/nvme/target/fcloop.c +++ b/drivers/nvme/target/fcloop.c @@ -300,7 +300,7 @@ fcloop_tgt_lsrqst_done_work(struct work_struct *work) struct fcloop_tport *tport = tls_req->tport; struct nvmefc_ls_req *lsreq = tls_req->lsreq; - if (tport->remoteport) + if (!tport || tport->remoteport) lsreq->done(lsreq, tls_req->status); } @@ -318,6 +318,7 @@ fcloop_ls_req(struct nvme_fc_local_port *localport, if (!rport->targetport) { tls_req->status = -ECONNREFUSED; + tls_req->tport = NULL; schedule_work(&tls_req->work); return ret; } diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c index 3333d417b248ba6de431adbb1562e40e9a9da751..a70b3d24936d3d7352cce7561835bea7394a2fa0 100644 --- a/drivers/nvme/target/rdma.c +++ b/drivers/nvme/target/rdma.c @@ -65,6 +65,7 @@ struct nvmet_rdma_rsp { struct nvmet_req req; + bool allocated; u8 n_rdma; u32 flags; u32 invalidate_rkey; @@ -167,11 +168,19 @@ nvmet_rdma_get_rsp(struct nvmet_rdma_queue *queue) unsigned long flags; spin_lock_irqsave(&queue->rsps_lock, flags); - rsp = list_first_entry(&queue->free_rsps, + rsp = list_first_entry_or_null(&queue->free_rsps, struct nvmet_rdma_rsp, free_list); - list_del(&rsp->free_list); + if (likely(rsp)) + list_del(&rsp->free_list); spin_unlock_irqrestore(&queue->rsps_lock, flags); + if (unlikely(!rsp)) { + rsp = kmalloc(sizeof(*rsp), GFP_KERNEL); + if (unlikely(!rsp)) + return NULL; + rsp->allocated = true; + } + return rsp; } @@ -180,6 +189,11 @@ nvmet_rdma_put_rsp(struct nvmet_rdma_rsp *rsp) { unsigned long flags; + if (rsp->allocated) { + kfree(rsp); + return; + } + spin_lock_irqsave(&rsp->queue->rsps_lock, flags); list_add_tail(&rsp->free_list, &rsp->queue->free_rsps); spin_unlock_irqrestore(&rsp->queue->rsps_lock, flags); @@ -756,6 +770,15 @@ static void nvmet_rdma_recv_done(struct ib_cq *cq, struct ib_wc *wc) cmd->queue = queue; rsp = nvmet_rdma_get_rsp(queue); + if (unlikely(!rsp)) { + /* + * we get here only under memory pressure, + * silently drop and have the host retry + * as we can't even fail it. + */ + nvmet_rdma_post_recv(queue->dev, cmd); + return; + } rsp->queue = queue; rsp->cmd = cmd; rsp->flags = 0; diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 2afafd5d8915088de1533881247fcb67b4a8aa4e..635886e4835cbb4b0a7836292c9bdd111ee0eb9c 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -865,6 +865,10 @@ struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *cell_id) return cell; } + /* NULL cell_id only allowed for device tree; invalid otherwise */ + if (!cell_id) + return ERR_PTR(-EINVAL); + return nvmem_cell_get_from_list(cell_id); } EXPORT_SYMBOL_GPL(nvmem_cell_get); diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index 985a85f281a82ea18d35937352891252dca3faa2..7c6aff761800971f8ca3eaa1781eda1b3752002b 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -614,6 +614,9 @@ static void __init of_unittest_parse_interrupts(void) struct of_phandle_args args; int i, rc; + if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC) + return; + np = of_find_node_by_path("/testcase-data/interrupts/interrupts0"); if (!np) { pr_err("missing testcase data\n"); @@ -688,6 +691,9 @@ static void __init of_unittest_parse_interrupts_extended(void) struct of_phandle_args args; int i, rc; + if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC) + return; + np = of_find_node_by_path("/testcase-data/interrupts/interrupts-extended0"); if (!np) { pr_err("missing testcase data\n"); @@ -844,15 +850,19 @@ static void __init of_unittest_platform_populate(void) pdev = of_find_device_by_node(np); unittest(pdev, "device 1 creation failed\n"); - irq = platform_get_irq(pdev, 0); - unittest(irq == -EPROBE_DEFER, "device deferred probe failed - %d\n", irq); + if (!(of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)) { + irq = platform_get_irq(pdev, 0); + unittest(irq == -EPROBE_DEFER, + "device deferred probe failed - %d\n", irq); - /* Test that a parsing failure does not return -EPROBE_DEFER */ - np = of_find_node_by_path("/testcase-data/testcase-device2"); - pdev = of_find_device_by_node(np); - unittest(pdev, "device 2 creation failed\n"); - irq = platform_get_irq(pdev, 0); - unittest(irq < 0 && irq != -EPROBE_DEFER, "device parsing error failed - %d\n", irq); + /* Test that a parsing failure does not return -EPROBE_DEFER */ + np = of_find_node_by_path("/testcase-data/testcase-device2"); + pdev = of_find_device_by_node(np); + unittest(pdev, "device 2 creation failed\n"); + irq = platform_get_irq(pdev, 0); + unittest(irq < 0 && irq != -EPROBE_DEFER, + "device parsing error failed - %d\n", irq); + } np = of_find_node_by_path("/testcase-data/platform-tests"); unittest(np, "No testcase data in device tree\n"); diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c index 01cf1c1a841a4de23af9e84f7c40cea7c552ca16..8de329546b8220783664f291ffd55b62144cdec5 100644 --- a/drivers/parport/parport_sunbpp.c +++ b/drivers/parport/parport_sunbpp.c @@ -286,12 +286,16 @@ static int bpp_probe(struct platform_device *op) ops = kmemdup(&parport_sunbpp_ops, sizeof(struct parport_operations), GFP_KERNEL); - if (!ops) + if (!ops) { + err = -ENOMEM; goto out_unmap; + } dprintk(("register_port\n")); - if (!(p = parport_register_port((unsigned long)base, irq, dma, ops))) + if (!(p = parport_register_port((unsigned long)base, irq, dma, ops))) { + err = -ENOMEM; goto out_free_ops; + } p->size = size; p->dev = &op->dev; diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index 6e125967b9f80bd2f1cee7f7ead74d41521183b5..fc43799452bcb122c7ce0c9c2c927643347d02e4 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig @@ -55,6 +55,16 @@ config PCI_MSM If unsure, say N. +config PCI_MSM_MSI + bool "MSM PCIe MSI support" + depends on PCI_MSM + depends on PCI_MSI_IRQ_DOMAIN + help + Say Y here if you want to enable MSI support for PCIe + controller and its devices. This controller offers + message signaled interrupts (MSI) allocation, routing, + masking, and affinity assigning for PCIe devices. + config PCI_RCAR_GEN2 bool "Renesas R-Car Gen2 Internal PCI controller" depends on ARM diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index 2ee6297b18ff364db1808ba5492d39a47addc2b1..b6a3f1b051a7e5d3c075eee51247e33f03a43d4e 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o obj-$(CONFIG_PCI_AARDVARK) += pci-aardvark.o obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o obj-$(CONFIG_PCI_MSM) += pci-msm.o +obj-$(CONFIG_PCI_MSM_MSI) += pci-msm-msi.o obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o obj-$(CONFIG_PCIE_RCAR) += pcie-rcar.o obj-$(CONFIG_PCI_HOST_COMMON) += pci-host-common.o diff --git a/drivers/pci/host/pci-aardvark.c b/drivers/pci/host/pci-aardvark.c index 9bfc22b5da4b718ffe7ed5e1d9805e0e9317fee7..5f3048e75becb598b14013382ed102fa59a6f5b4 100644 --- a/drivers/pci/host/pci-aardvark.c +++ b/drivers/pci/host/pci-aardvark.c @@ -954,6 +954,7 @@ static int advk_pcie_probe(struct platform_device *pdev) bus = bridge->bus; + pci_bus_size_bridges(bus); pci_bus_assign_resources(bus); list_for_each_entry(child, &bus->children, node) diff --git a/drivers/pci/host/pci-ftpci100.c b/drivers/pci/host/pci-ftpci100.c index 4ea7d2ebcc5cd4ed4e3702947152c72054a06efe..4e6b219315142b67e05200fd8f5f250f112b9586 100644 --- a/drivers/pci/host/pci-ftpci100.c +++ b/drivers/pci/host/pci-ftpci100.c @@ -353,11 +353,13 @@ static int faraday_pci_setup_cascaded_irq(struct faraday_pci *p) irq = of_irq_get(intc, 0); if (irq <= 0) { dev_err(p->dev, "failed to get parent IRQ\n"); + of_node_put(intc); return irq ?: -EINVAL; } p->irqdomain = irq_domain_add_linear(intc, PCI_NUM_INTX, &faraday_pci_irqdomain_ops, p); + of_node_put(intc); if (!p->irqdomain) { dev_err(p->dev, "failed to create Gemini PCI IRQ domain\n"); return -EINVAL; diff --git a/drivers/pci/host/pci-host-common.c b/drivers/pci/host/pci-host-common.c index 44a47d4f0b8f294fef5c2b2482b0a16856849f01..148896f73c06f8eca9ab6cb99c9b3b98f569dab6 100644 --- a/drivers/pci/host/pci-host-common.c +++ b/drivers/pci/host/pci-host-common.c @@ -45,7 +45,7 @@ static int gen_pci_parse_request_of_pci_ranges(struct device *dev, switch (resource_type(res)) { case IORESOURCE_IO: - err = pci_remap_iospace(res, iobase); + err = devm_pci_remap_iospace(dev, res, iobase); if (err) { dev_warn(dev, "error %d: failed to map resource %pR\n", err, res); diff --git a/drivers/pci/host/pci-hyperv.c b/drivers/pci/host/pci-hyperv.c index 4523d7e1bcb9c7d66528105306bf3b688c8a1e05..ffc87a956d97460e9e1bca6e3b02c78c65f65b0a 100644 --- a/drivers/pci/host/pci-hyperv.c +++ b/drivers/pci/host/pci-hyperv.c @@ -53,6 +53,8 @@ #include #include #include +#include + #include #include #include diff --git a/drivers/pci/host/pci-msm-msi.c b/drivers/pci/host/pci-msm-msi.c new file mode 100644 index 0000000000000000000000000000000000000000..4760e08b582cf3fd2d10f4fb9efe4aa8b5c83fda --- /dev/null +++ b/drivers/pci/host/pci-msm-msi.c @@ -0,0 +1,385 @@ +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * MSM PCIe MSI controller + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct msm_msi_irq { + unsigned int hwirq; /* MSI controller hwirq */ + unsigned int virq; /* MSI controller virq */ +}; + +struct msm_msi { + struct list_head clients; + struct device *dev; + struct device_node *of_node; + int nr_irqs; + struct msm_msi_irq *irqs; + unsigned long *bitmap; /* tracks used/unused MSI */ + struct mutex mutex; /* mutex for modifying MSI client list and bitmap */ + struct irq_domain *inner_domain; /* parent domain; gen irq related */ + struct irq_domain *msi_domain; /* child domain; pci related */ + phys_addr_t msi_addr; +}; + +/* structure for each client of MSI controller */ +struct msm_msi_client { + struct list_head node; + struct msm_msi *msi; + struct device *dev; /* client's dev of pci_dev */ + u32 nr_irqs; /* nr_irqs allocated for client */ + dma_addr_t msi_addr; +}; + +static void msm_msi_handler(struct irq_desc *desc) +{ + struct irq_chip *chip = irq_desc_get_chip(desc); + struct msm_msi *msi; + unsigned int virq; + + chained_irq_enter(chip, desc); + + msi = irq_desc_get_handler_data(desc); + virq = irq_find_mapping(msi->inner_domain, irq_desc_get_irq(desc)); + + generic_handle_irq(virq); + + chained_irq_exit(chip, desc); +} + +static struct irq_chip msm_msi_irq_chip = { + .name = "msm_pci_msi", + .irq_mask = pci_msi_mask_irq, + .irq_unmask = pci_msi_unmask_irq, +}; + +static int msm_msi_domain_prepare(struct irq_domain *domain, struct device *dev, + int nvec, msi_alloc_info_t *arg) +{ + struct msm_msi *msi = domain->parent->host_data; + struct msm_msi_client *client; + + client = devm_kzalloc(msi->dev, sizeof(*client), GFP_KERNEL); + if (!client) + return -ENOMEM; + + client->msi = msi; + client->dev = dev; + client->msi_addr = dma_map_resource(client->dev, msi->msi_addr, + PAGE_SIZE, DMA_FROM_DEVICE, 0); + if (dma_mapping_error(client->dev, client->msi_addr)) { + dev_err(msi->dev, "MSI: failed to map msi address\n"); + client->msi_addr = 0; + return -ENOMEM; + } + + mutex_lock(&msi->mutex); + list_add_tail(&client->node, &msi->clients); + mutex_unlock(&msi->mutex); + + /* zero out struct for framework */ + memset(arg, 0, sizeof(*arg)); + + return 0; +} + +void msm_msi_domain_finish(msi_alloc_info_t *arg, int retval) +{ + struct device *dev = arg->desc->dev; + struct irq_domain *domain = dev_get_msi_domain(dev); + struct msm_msi *msi = domain->parent->host_data; + + /* if prepare or alloc fails, then clean up */ + if (retval) { + struct msm_msi_client *tmp, *client = NULL; + + mutex_lock(&msi->mutex); + list_for_each_entry(tmp, &msi->clients, node) { + if (tmp->dev == dev) { + client = tmp; + list_del(&client->node); + break; + } + } + mutex_unlock(&msi->mutex); + + if (!client) + return; + + if (client->msi_addr) + dma_unmap_resource(client->dev, client->msi_addr, + PAGE_SIZE, DMA_FROM_DEVICE, 0); + + devm_kfree(msi->dev, client); + + return; + } +} + +static struct msi_domain_ops msm_msi_domain_ops = { + .msi_prepare = msm_msi_domain_prepare, + .msi_finish = msm_msi_domain_finish, +}; + +static struct msi_domain_info msm_msi_domain_info = { + .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | + MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX, + .ops = &msm_msi_domain_ops, + .chip = &msm_msi_irq_chip, +}; + +static int msm_msi_irq_set_affinity(struct irq_data *data, + const struct cpumask *mask, bool force) +{ + struct irq_data *parent_data = irq_get_irq_data(irqd_to_hwirq(data)); + + /* set affinity for MSM MSI HW IRQ */ + if (parent_data->chip->irq_set_affinity) + return parent_data->chip->irq_set_affinity(parent_data, + mask, force); + + return -EINVAL; +} + +static void msm_msi_irq_compose_msi_msg(struct irq_data *data, + struct msi_msg *msg) +{ + struct msm_msi_client *client = irq_data_get_irq_chip_data(data); + struct irq_data *parent_data = irq_get_irq_data(irqd_to_hwirq(data)); + + msg->address_lo = lower_32_bits(client->msi_addr); + msg->address_hi = upper_32_bits(client->msi_addr); + + /* GIC HW IRQ */ + msg->data = irqd_to_hwirq(parent_data); +} + +static struct irq_chip msm_msi_bottom_irq_chip = { + .name = "msm_msi", + .irq_set_affinity = msm_msi_irq_set_affinity, + .irq_compose_msi_msg = msm_msi_irq_compose_msi_msg, +}; + +static int msm_msi_irq_domain_alloc(struct irq_domain *domain, + unsigned int virq, unsigned int nr_irqs, + void *args) +{ + struct msm_msi *msi = domain->host_data; + struct msm_msi_client *tmp, *client = NULL; + struct device *dev = ((msi_alloc_info_t *)args)->desc->dev; + int i, ret = 0; + int pos; + + mutex_lock(&msi->mutex); + list_for_each_entry(tmp, &msi->clients, node) { + if (tmp->dev == dev) { + client = tmp; + break; + } + } + + if (!client) { + dev_err(msi->dev, "MSI: failed to find client dev\n"); + ret = -ENODEV; + goto out; + } + + pos = bitmap_find_next_zero_area(msi->bitmap, msi->nr_irqs, 0, + nr_irqs, 0); + if (pos < msi->nr_irqs) { + bitmap_set(msi->bitmap, pos, nr_irqs); + } else { + ret = -ENOSPC; + goto out; + } + + for (i = 0; i < nr_irqs; i++) { + msi->irqs[pos].virq = virq + i; + irq_domain_set_info(domain, msi->irqs[pos].virq, + msi->irqs[pos].hwirq, + &msm_msi_bottom_irq_chip, client, + handle_simple_irq, NULL, NULL); + client->nr_irqs++; + pos++; + } + +out: + mutex_unlock(&msi->mutex); + return ret; +} + +static void msm_msi_irq_domain_free(struct irq_domain *domain, + unsigned int virq, unsigned int nr_irqs) +{ + struct irq_data *data = irq_domain_get_irq_data(domain, virq); + struct msm_msi_client *client = irq_data_get_irq_chip_data(data); + struct msm_msi *msi = client->msi; + int i; + + mutex_lock(&msi->mutex); + for (i = 0; i < nr_irqs; i++) + if (msi->irqs[i].virq == virq) + break; + + bitmap_clear(msi->bitmap, i, nr_irqs); + client->nr_irqs -= nr_irqs; + + if (!client->nr_irqs) { + dma_unmap_resource(client->dev, client->msi_addr, PAGE_SIZE, + DMA_FROM_DEVICE, 0); + list_del(&client->node); + devm_kfree(msi->dev, client); + } + + mutex_unlock(&msi->mutex); + + irq_domain_free_irqs_parent(domain, virq, nr_irqs); +} + +static const struct irq_domain_ops msi_domain_ops = { + .alloc = msm_msi_irq_domain_alloc, + .free = msm_msi_irq_domain_free, +}; + +static int msm_msi_alloc_domains(struct msm_msi *msi) +{ + msi->inner_domain = irq_domain_add_linear(NULL, msi->nr_irqs, + &msi_domain_ops, msi); + if (!msi->inner_domain) { + dev_err(msi->dev, "MSI: failed to create IRQ domain\n"); + return -ENOMEM; + } + + msi->msi_domain = pci_msi_create_irq_domain( + of_node_to_fwnode(msi->of_node), + &msm_msi_domain_info, + msi->inner_domain); + if (!msi->msi_domain) { + dev_err(msi->dev, "MSI: failed to create MSI domain\n"); + irq_domain_remove(msi->inner_domain); + return -ENOMEM; + } + + return 0; +} + +int msm_msi_init(struct device *dev) +{ + int i, ret; + struct msm_msi *msi; + struct device_node *of_node; + const __be32 *prop_val; + + if (!dev->of_node) { + dev_err(dev, "MSI: missing DT node\n"); + return -EINVAL; + } + + of_node = of_parse_phandle(dev->of_node, "msi-parent", 0); + if (!of_node) { + dev_err(dev, "MSI: no phandle for MSI found\n"); + return -ENODEV; + } + + if (!of_device_is_compatible(of_node, "qcom,pci-msi")) { + dev_err(dev, "MSI: no compatible qcom,pci-msi found\n"); + return -ENODEV; + } + + if (!of_find_property(of_node, "msi-controller", NULL)) + return -ENODEV; + + msi = devm_kzalloc(dev, sizeof(*msi), GFP_KERNEL); + if (!msi) + return -ENOMEM; + + msi->dev = dev; + msi->of_node = of_node; + mutex_init(&msi->mutex); + INIT_LIST_HEAD(&msi->clients); + + prop_val = of_get_address(msi->of_node, 0, NULL, NULL); + if (!prop_val) { + dev_err(msi->dev, "MSI: missing 'reg' devicetree\n"); + return -EINVAL; + } + + msi->msi_addr = be32_to_cpup(prop_val); + if (!msi->msi_addr) { + dev_err(msi->dev, "MSI: failed to get MSI address\n"); + return -EINVAL; + } + + msi->nr_irqs = of_irq_count(msi->of_node); + if (!msi->nr_irqs) { + dev_err(msi->dev, "MSI: found no MSI interrupts\n"); + return -ENODEV; + } + + msi->irqs = devm_kcalloc(msi->dev, msi->nr_irqs, + sizeof(*msi->irqs), GFP_KERNEL); + if (!msi->irqs) + return -ENOMEM; + + msi->bitmap = devm_kcalloc(msi->dev, BITS_TO_LONGS(msi->nr_irqs), + sizeof(*msi->bitmap), GFP_KERNEL); + if (!msi->bitmap) + return -ENOMEM; + + ret = msm_msi_alloc_domains(msi); + if (ret) { + dev_err(msi->dev, "MSI: failed to allocate MSI domains\n"); + return ret; + } + + for (i = 0; i < msi->nr_irqs; i++) { + unsigned int irq = irq_of_parse_and_map(msi->of_node, i); + + if (!irq) { + dev_err(msi->dev, + "MSI: failed to parse/map interrupt\n"); + ret = -ENODEV; + goto free_irqs; + } + + msi->irqs[i].hwirq = irq; + irq_set_chained_handler_and_data(msi->irqs[i].hwirq, + msm_msi_handler, msi); + } + + return 0; + +free_irqs: + for (--i; i >= 0; i--) { + irq_set_chained_handler_and_data(msi->irqs[i].hwirq, + NULL, NULL); + irq_dispose_mapping(msi->irqs[i].hwirq); + } + + irq_domain_remove(msi->msi_domain); + irq_domain_remove(msi->inner_domain); + + return ret; +} +EXPORT_SYMBOL(msm_msi_init); diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c index 8d88f19dc171145a74e8a87345796406f1c0ec37..12c1c1851ee6308b043a1a4db37a18ec3304ec2d 100644 --- a/drivers/pci/host/pci-mvebu.c +++ b/drivers/pci/host/pci-mvebu.c @@ -1220,7 +1220,7 @@ static int mvebu_pcie_probe(struct platform_device *pdev) pcie->realio.start = PCIBIOS_MIN_IO; pcie->realio.end = min_t(resource_size_t, IO_SPACE_LIMIT, - resource_size(&pcie->io)); + resource_size(&pcie->io) - 1); } else pcie->realio = pcie->io; diff --git a/drivers/pci/host/pci-versatile.c b/drivers/pci/host/pci-versatile.c index d417acab0ecf7baa81fca755a97238cc1232131f..aff4cfb555fbbba74c122cc4efdb611546388ea3 100644 --- a/drivers/pci/host/pci-versatile.c +++ b/drivers/pci/host/pci-versatile.c @@ -89,7 +89,7 @@ static int versatile_pci_parse_request_of_pci_ranges(struct device *dev, switch (resource_type(res)) { case IORESOURCE_IO: - err = pci_remap_iospace(res, iobase); + err = devm_pci_remap_iospace(dev, res, iobase); if (err) { dev_warn(dev, "error %d: failed to map resource %pR\n", err, res); diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c index 8f44a7d14bffa046ce25700807b2bbf27cefc1d6..41edce16a07cdcebd9df7f6ef466d9f28babb545 100644 --- a/drivers/pci/host/pcie-rcar.c +++ b/drivers/pci/host/pcie-rcar.c @@ -1105,7 +1105,7 @@ static int rcar_pcie_parse_request_of_pci_ranges(struct rcar_pcie *pci) struct resource *res = win->res; if (resource_type(res) == IORESOURCE_IO) { - err = pci_remap_iospace(res, iobase); + err = devm_pci_remap_iospace(dev, res, iobase); if (err) { dev_warn(dev, "error %d: failed to map resource %pR\n", err, res); diff --git a/drivers/pci/host/pcie-xilinx-nwl.c b/drivers/pci/host/pcie-xilinx-nwl.c index 65dea98b2643fb18469799a9e784ce8571416912..dd527ea558d71d51c1caff9593f43694f15a308c 100644 --- a/drivers/pci/host/pcie-xilinx-nwl.c +++ b/drivers/pci/host/pcie-xilinx-nwl.c @@ -561,7 +561,7 @@ static int nwl_pcie_init_irq_domain(struct nwl_pcie *pcie) PCI_NUM_INTX, &legacy_domain_ops, pcie); - + of_node_put(legacy_intc_node); if (!pcie->legacy_irq_domain) { dev_err(dev, "failed to create IRQ domain\n"); return -ENOMEM; diff --git a/drivers/pci/host/pcie-xilinx.c b/drivers/pci/host/pcie-xilinx.c index 94e13cb8608f179ba8e25d30dfd9436517bd55db..29f024f0ed7f2c2e8c0ab134a9f7949f09e8a9f8 100644 --- a/drivers/pci/host/pcie-xilinx.c +++ b/drivers/pci/host/pcie-xilinx.c @@ -511,6 +511,7 @@ static int xilinx_pcie_init_irq_domain(struct xilinx_pcie_port *port) port->leg_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX, &intx_domain_ops, port); + of_node_put(pcie_intc_node); if (!port->leg_domain) { dev_err(dev, "Failed to get a INTx IRQ domain\n"); return -ENODEV; diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index 7b0e97be9063d971dbd327836ab1c9cd2377287d..591f2e05ab1c3c1f7dc47b5d38c0aa390fdc72de 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -452,8 +452,17 @@ int __pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, list_add(&slot->slot_list, &pci_hotplug_slot_list); result = fs_add_slot(pci_slot); + if (result) + goto err_list_del; + kobject_uevent(&pci_slot->kobj, KOBJ_ADD); dbg("Added slot %s to the list\n", name); + goto out; + +err_list_del: + list_del(&slot->slot_list); + pci_slot->hotplug = NULL; + pci_destroy_slot(pci_slot); out: mutex_unlock(&pci_hp_mutex); return result; diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index e7d6cfaf386581a7d89541c89298d235bde752d6..9fc4357c3db940312c7caf86e3e5cab8866316a7 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -132,6 +132,7 @@ int pciehp_unconfigure_device(struct slot *p_slot); void pciehp_queue_pushbutton_work(struct work_struct *work); struct controller *pcie_init(struct pcie_device *dev); int pcie_init_notification(struct controller *ctrl); +void pcie_shutdown_notification(struct controller *ctrl); int pciehp_enable_slot(struct slot *p_slot); int pciehp_disable_slot(struct slot *p_slot); void pcie_reenable_notification(struct controller *ctrl); diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 1288289cc85d38fa09190586f7743ac1271e5a83..c38e392d63e4b2037b1c1cbb879b3d1239ec8a80 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -76,6 +76,12 @@ static int reset_slot(struct hotplug_slot *slot, int probe); */ static void release_slot(struct hotplug_slot *hotplug_slot) { + struct slot *slot = hotplug_slot->private; + + /* queued work needs hotplug_slot name */ + cancel_delayed_work(&slot->work); + drain_workqueue(slot->wq); + kfree(hotplug_slot->ops); kfree(hotplug_slot->info); kfree(hotplug_slot); @@ -278,6 +284,7 @@ static void pciehp_remove(struct pcie_device *dev) { struct controller *ctrl = get_service_data(dev); + pcie_shutdown_notification(ctrl); cleanup_slot(ctrl); pciehp_release_ctrl(ctrl); } diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 46c2ee2caf281680aa280f1a386f4d059d110888..2fa830727362939ef0446940d308ad5500244c35 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -562,8 +562,6 @@ static irqreturn_t pciehp_isr(int irq, void *dev_id) { struct controller *ctrl = (struct controller *)dev_id; struct pci_dev *pdev = ctrl_dev(ctrl); - struct pci_bus *subordinate = pdev->subordinate; - struct pci_dev *dev; struct slot *slot = ctrl->slot; u16 status, events; u8 present; @@ -611,14 +609,9 @@ static irqreturn_t pciehp_isr(int irq, void *dev_id) wake_up(&ctrl->queue); } - if (subordinate) { - list_for_each_entry(dev, &subordinate->devices, bus_list) { - if (dev->ignore_hotplug) { - ctrl_dbg(ctrl, "ignoring hotplug event %#06x (%s requested no hotplug)\n", - events, pci_name(dev)); - return IRQ_HANDLED; - } - } + if (pdev->ignore_hotplug) { + ctrl_dbg(ctrl, "ignoring hotplug event %#06x\n", events); + return IRQ_HANDLED; } /* Check Attention Button Pressed */ @@ -789,7 +782,7 @@ int pcie_init_notification(struct controller *ctrl) return 0; } -static void pcie_shutdown_notification(struct controller *ctrl) +void pcie_shutdown_notification(struct controller *ctrl) { if (ctrl->notification_enabled) { pcie_disable_notification(ctrl); @@ -824,7 +817,7 @@ static int pcie_init_slot(struct controller *ctrl) static void pcie_cleanup_slot(struct controller *ctrl) { struct slot *slot = ctrl->slot; - cancel_delayed_work(&slot->work); + destroy_workqueue(slot->wq); kfree(slot); } @@ -912,7 +905,6 @@ struct controller *pcie_init(struct pcie_device *dev) void pciehp_release_ctrl(struct controller *ctrl) { - pcie_shutdown_notification(ctrl); pcie_cleanup_slot(ctrl); kfree(ctrl); } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 62a0677b32f100989b40e96985534ae3063121ac..1af30c8815665eea6e7deab98cdf2d29c81e253d 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1112,12 +1112,12 @@ int pci_save_state(struct pci_dev *dev) EXPORT_SYMBOL(pci_save_state); static void pci_restore_config_dword(struct pci_dev *pdev, int offset, - u32 saved_val, int retry) + u32 saved_val, int retry, bool force) { u32 val; pci_read_config_dword(pdev, offset, &val); - if (val == saved_val) + if (!force && val == saved_val) return; for (;;) { @@ -1136,25 +1136,36 @@ static void pci_restore_config_dword(struct pci_dev *pdev, int offset, } static void pci_restore_config_space_range(struct pci_dev *pdev, - int start, int end, int retry) + int start, int end, int retry, + bool force) { int index; for (index = end; index >= start; index--) pci_restore_config_dword(pdev, 4 * index, pdev->saved_config_space[index], - retry); + retry, force); } static void pci_restore_config_space(struct pci_dev *pdev) { if (pdev->hdr_type == PCI_HEADER_TYPE_NORMAL) { - pci_restore_config_space_range(pdev, 10, 15, 0); + pci_restore_config_space_range(pdev, 10, 15, 0, false); /* Restore BARs before the command register. */ - pci_restore_config_space_range(pdev, 4, 9, 10); - pci_restore_config_space_range(pdev, 0, 3, 0); + pci_restore_config_space_range(pdev, 4, 9, 10, false); + pci_restore_config_space_range(pdev, 0, 3, 0, false); + } else if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + pci_restore_config_space_range(pdev, 12, 15, 0, false); + + /* + * Force rewriting of prefetch registers to avoid S3 resume + * issues on Intel PCI bridges that occur when these + * registers are not explicitly written. + */ + pci_restore_config_space_range(pdev, 9, 11, 0, true); + pci_restore_config_space_range(pdev, 0, 8, 0, false); } else { - pci_restore_config_space_range(pdev, 0, 15, 0); + pci_restore_config_space_range(pdev, 0, 15, 0, false); } } @@ -3446,6 +3457,44 @@ void pci_unmap_iospace(struct resource *res) } EXPORT_SYMBOL(pci_unmap_iospace); +static void devm_pci_unmap_iospace(struct device *dev, void *ptr) +{ + struct resource **res = ptr; + + pci_unmap_iospace(*res); +} + +/** + * devm_pci_remap_iospace - Managed pci_remap_iospace() + * @dev: Generic device to remap IO address for + * @res: Resource describing the I/O space + * @phys_addr: physical address of range to be mapped + * + * Managed pci_remap_iospace(). Map is automatically unmapped on driver + * detach. + */ +int devm_pci_remap_iospace(struct device *dev, const struct resource *res, + phys_addr_t phys_addr) +{ + const struct resource **ptr; + int error; + + ptr = devres_alloc(devm_pci_unmap_iospace, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + error = pci_remap_iospace(res, phys_addr); + if (error) { + devres_free(ptr); + } else { + *ptr = res; + devres_add(dev, ptr); + } + + return error; +} +EXPORT_SYMBOL(devm_pci_remap_iospace); + /** * devm_pci_remap_cfgspace - Managed pci_remap_cfgspace() * @dev: Generic device to remap IO address for diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 4bccaf688aad7c7d5ed73b89b1b4f118c0a6690b..e23bfd9845b12f3808e88838bbb1bdec5c4dcc81 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1560,6 +1560,10 @@ static void pci_configure_mps(struct pci_dev *dev) if (!pci_is_pcie(dev) || !bridge || !pci_is_pcie(bridge)) return; + /* MPS and MRRS fields are of type 'RsvdP' for VFs, short-circuit out */ + if (dev->is_virtfn) + return; + mps = pcie_get_mps(dev); p_mps = pcie_get_mps(bridge); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index ec2911c4ee425e7cde8ee990aa78848cfa96f8e1..35c9b2f4b293aae36cb0fee4cdd49982784c13f8 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4388,11 +4388,6 @@ static int pci_quirk_qcom_rp_acs(struct pci_dev *dev, u16 acs_flags) * * 0x9d10-0x9d1b PCI Express Root port #{1-12} * - * The 300 series chipset suffers from the same bug so include those root - * ports here as well. - * - * 0xa32c-0xa343 PCI Express Root port #{0-24} - * * [1] http://www.intel.com/content/www/us/en/chipsets/100-series-chipset-datasheet-vol-2.html * [2] http://www.intel.com/content/www/us/en/chipsets/100-series-chipset-datasheet-vol-1.html * [3] http://www.intel.com/content/www/us/en/chipsets/100-series-chipset-spec-update.html @@ -4410,7 +4405,6 @@ static bool pci_quirk_intel_spt_pch_acs_match(struct pci_dev *dev) case 0xa110 ... 0xa11f: case 0xa167 ... 0xa16a: /* Sunrise Point */ case 0xa290 ... 0xa29f: case 0xa2e7 ... 0xa2ee: /* Union Point */ case 0x9d10 ... 0x9d1b: /* 7th & 8th Gen Mobile */ - case 0xa32c ... 0xa343: /* 300 series */ return true; } diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index af81b2dec42e954692fe85ef2992ecf82fc44cb3..620f5b995a129d8a6409a3181dfe8951fd32d408 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -24,6 +24,8 @@ #include #include +#include + MODULE_DESCRIPTION("Microsemi Switchtec(tm) PCIe Management Driver"); MODULE_VERSION("0.1"); MODULE_LICENSE("GPL"); @@ -1173,6 +1175,8 @@ static int ioctl_port_to_pff(struct switchtec_dev *stdev, default: if (p.port > ARRAY_SIZE(pcfg->dsp_pff_inst_id)) return -EINVAL; + p.port = array_index_nospec(p.port, + ARRAY_SIZE(pcfg->dsp_pff_inst_id) + 1); p.pff = ioread32(&pcfg->dsp_pff_inst_id[p.port - 1]); break; } diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index 2288889ebfe9822974198468e254cabd6d583e0f..30972755dd46e37d503efe995e3f953b2ebd688e 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c @@ -662,11 +662,7 @@ static void cpu_pm_pmu_setup(struct arm_pmu *armpmu, unsigned long cmd) if (!event) continue; - /* - * Check if an attempt was made to free this event during - * the CPU went offline. - */ - if (event->state == PERF_EVENT_STATE_ZOMBIE) + if (event->state != PERF_EVENT_STATE_ACTIVE) continue; switch (cmd) { @@ -792,10 +788,8 @@ static int arm_perf_starting_cpu(unsigned int cpu, struct hlist_node *node) if (!pmu || !cpumask_test_cpu(cpu, &pmu->supported_cpus)) return 0; - data.cmd = CPU_PM_EXIT; - cpu_pm_pmu_common(&data); - if (data.ret == NOTIFY_DONE) - return 0; + if (pmu->reset) + pmu->reset(pmu); if (data.armpmu->pmu_state != ARM_PMU_STATE_OFF && data.armpmu->plat_device) { @@ -821,8 +815,6 @@ static int arm_perf_stopping_cpu(unsigned int cpu, struct hlist_node *node) if (!pmu || !cpumask_test_cpu(cpu, &pmu->supported_cpus)) return 0; - data.cmd = CPU_PM_ENTER; - cpu_pm_pmu_common(&data); /* Disarm the PMU IRQ before disappearing. */ if (data.armpmu->pmu_state == ARM_PMU_STATE_RUNNING && data.armpmu->plat_device) { diff --git a/drivers/perf/xgene_pmu.c b/drivers/perf/xgene_pmu.c index eb23311bc70c042319909206fa4f015c7da4c905..8b79c2f7931f1711b4ed85b7f8a90123788c484a 100644 --- a/drivers/perf/xgene_pmu.c +++ b/drivers/perf/xgene_pmu.c @@ -1463,7 +1463,7 @@ static char *xgene_pmu_dev_name(struct device *dev, u32 type, int id) case PMU_TYPE_IOB: return devm_kasprintf(dev, GFP_KERNEL, "iob%d", id); case PMU_TYPE_IOB_SLOW: - return devm_kasprintf(dev, GFP_KERNEL, "iob-slow%d", id); + return devm_kasprintf(dev, GFP_KERNEL, "iob_slow%d", id); case PMU_TYPE_MCB: return devm_kasprintf(dev, GFP_KERNEL, "mcb%d", id); case PMU_TYPE_MC: diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c index 721a2a1c97ef43299c3e143744297764943b4b92..a63bba12aee42a01c8478d9647fe2873abc97076 100644 --- a/drivers/phy/mediatek/phy-mtk-tphy.c +++ b/drivers/phy/mediatek/phy-mtk-tphy.c @@ -438,9 +438,9 @@ static void u2_phy_instance_init(struct mtk_tphy *tphy, u32 index = instance->index; u32 tmp; - /* switch to USB function. (system register, force ip into usb mode) */ + /* switch to USB function, and enable usb pll */ tmp = readl(com + U3P_U2PHYDTM0); - tmp &= ~P2C_FORCE_UART_EN; + tmp &= ~(P2C_FORCE_UART_EN | P2C_FORCE_SUSPENDM); tmp |= P2C_RG_XCVRSEL_VAL(1) | P2C_RG_DATAIN_VAL(0); writel(tmp, com + U3P_U2PHYDTM0); @@ -500,10 +500,8 @@ static void u2_phy_instance_power_on(struct mtk_tphy *tphy, u32 index = instance->index; u32 tmp; - /* (force_suspendm=0) (let suspendm=1, enable usb 480MHz pll) */ tmp = readl(com + U3P_U2PHYDTM0); - tmp &= ~(P2C_FORCE_SUSPENDM | P2C_RG_XCVRSEL); - tmp &= ~(P2C_RG_DATAIN | P2C_DTM0_PART_MASK); + tmp &= ~(P2C_RG_XCVRSEL | P2C_RG_DATAIN | P2C_DTM0_PART_MASK); writel(tmp, com + U3P_U2PHYDTM0); /* OTG Enable */ @@ -538,7 +536,6 @@ static void u2_phy_instance_power_off(struct mtk_tphy *tphy, tmp = readl(com + U3P_U2PHYDTM0); tmp &= ~(P2C_RG_XCVRSEL | P2C_RG_DATAIN); - tmp |= P2C_FORCE_SUSPENDM; writel(tmp, com + U3P_U2PHYDTM0); /* OTG Disable */ @@ -546,18 +543,16 @@ static void u2_phy_instance_power_off(struct mtk_tphy *tphy, tmp &= ~PA6_RG_U2_OTG_VBUSCMP_EN; writel(tmp, com + U3P_USBPHYACR6); - /* let suspendm=0, set utmi into analog power down */ - tmp = readl(com + U3P_U2PHYDTM0); - tmp &= ~P2C_RG_SUSPENDM; - writel(tmp, com + U3P_U2PHYDTM0); - udelay(1); - tmp = readl(com + U3P_U2PHYDTM1); tmp &= ~(P2C_RG_VBUSVALID | P2C_RG_AVALID); tmp |= P2C_RG_SESSEND; writel(tmp, com + U3P_U2PHYDTM1); if (tphy->pdata->avoid_rx_sen_degradation && index) { + tmp = readl(com + U3P_U2PHYDTM0); + tmp &= ~(P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM); + writel(tmp, com + U3P_U2PHYDTM0); + tmp = readl(com + U3D_U2PHYDCR0); tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON; writel(tmp, com + U3D_U2PHYDCR0); diff --git a/drivers/phy/qualcomm/Kconfig b/drivers/phy/qualcomm/Kconfig index 7bfa64baf83772d465964a30ef1bec545fbc4366..5ccc2410a34beee143402be4bf95c50cbe5fdbab 100644 --- a/drivers/phy/qualcomm/Kconfig +++ b/drivers/phy/qualcomm/Kconfig @@ -15,6 +15,14 @@ config PHY_QCOM_IPQ806X_SATA depends on OF select GENERIC_PHY +config PHY_QCOM_PCIE2 + tristate "Qualcomm PCIe PHY Driver" + depends on OF && COMMON_CLK && (ARCH_QCOM || COMPILE_TEST) + select GENERIC_PHY + help + Enable this to support the Qualcomm PCIe PHY, used with the Synopsys + based PCIe controller. + config PHY_QCOM_QMP tristate "Qualcomm QMP PHY Driver" depends on OF && COMMON_CLK && (ARCH_QCOM || COMPILE_TEST) diff --git a/drivers/phy/qualcomm/Makefile b/drivers/phy/qualcomm/Makefile index 6189a5b85ba627868eed2d18baed2905639f95a4..e210f34c00bd33029929dd2885c6f3ed70374272 100644 --- a/drivers/phy/qualcomm/Makefile +++ b/drivers/phy/qualcomm/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o +obj-$(CONFIG_PHY_QCOM_PCIE2) += phy-qcom-pcie2.o obj-$(CONFIG_PHY_QCOM_QMP) += phy-qcom-qmp.o obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o diff --git a/drivers/phy/qualcomm/phy-qcom-pcie2.c b/drivers/phy/qualcomm/phy-qcom-pcie2.c new file mode 100644 index 0000000000000000000000000000000000000000..c29508d23706490b7b30d53520898e200bca9ebc --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-pcie2.c @@ -0,0 +1,267 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2018, Linaro Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define PCIE20_PARF_PHY_STTS 0x3c +#define PCIE2_PHY_RESET_CTRL 0x44 +#define PCIE20_PARF_PHY_REFCLK_CTRL2 0xa0 +#define PCIE20_PARF_PHY_REFCLK_CTRL3 0xa4 +#define PCIE20_PARF_PCS_SWING_CTRL1 0x88 +#define PCIE20_PARF_PCS_SWING_CTRL2 0x8c +#define PCIE20_PARF_PCS_DEEMPH1 0x74 +#define PCIE20_PARF_PCS_DEEMPH2 0x78 +#define PCIE20_PARF_PCS_DEEMPH3 0x7c +#define PCIE20_PARF_CONFIGBITS 0x84 +#define PCIE20_PARF_PHY_CTRL3 0x94 +#define PCIE20_PARF_PCS_CTRL 0x80 + +#define TX_AMP_VAL 120 +#define PHY_RX0_EQ_GEN1_VAL 0 +#define PHY_RX0_EQ_GEN2_VAL 4 +#define TX_DEEMPH_GEN1_VAL 24 +#define TX_DEEMPH_GEN2_3_5DB_VAL 26 +#define TX_DEEMPH_GEN2_6DB_VAL 36 +#define PHY_TX0_TERM_OFFST_VAL 0 + +struct qcom_phy { + struct device *dev; + void __iomem *base; + + struct reset_control *pipe_reset; + struct clk *pipe_clk; +}; + +static int qcom_pcie2_phy_power_on(struct phy *phy) { + struct qcom_phy *qphy = phy_get_drvdata(phy); + int ret; + u32 val; + + /* Program REF_CLK source */ + val = readl(qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2); + val &= ~BIT(1); + writel(val, qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2); + + usleep_range(1000, 2000); + + /* Don't use PAD for refclock */ + val = readl(qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2); + val &= ~BIT(0); + writel(val, qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL2); + + /* Program SSP ENABLE */ + val = readl(qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL3); + val |= BIT(0); + writel(val, qphy->base + PCIE20_PARF_PHY_REFCLK_CTRL3); + + usleep_range(1000, 2000); + + /* Assert Phy SW Reset */ + val = readl(qphy->base + PCIE2_PHY_RESET_CTRL); + val |= BIT(0); + writel(val, qphy->base + PCIE2_PHY_RESET_CTRL); + + /* Program Tx Amplitude */ + val = readl(qphy->base + PCIE20_PARF_PCS_SWING_CTRL1); + val &= ~0x7f; + val |= TX_AMP_VAL; + writel(val, qphy->base + PCIE20_PARF_PCS_SWING_CTRL1); + + val = readl(qphy->base + PCIE20_PARF_PCS_SWING_CTRL2); + val &= ~0x7f; + val |= TX_AMP_VAL; + writel(val, qphy->base + PCIE20_PARF_PCS_SWING_CTRL2); + + /* Program De-Emphasis */ + val = readl(qphy->base + PCIE20_PARF_PCS_DEEMPH1); + val &= ~0x3f; + val |= TX_DEEMPH_GEN2_6DB_VAL; + writel(val, qphy->base + PCIE20_PARF_PCS_DEEMPH1); + + val = readl(qphy->base + PCIE20_PARF_PCS_DEEMPH2); + val &= ~0x3f; + val |= TX_DEEMPH_GEN2_3_5DB_VAL; + writel(val, qphy->base + PCIE20_PARF_PCS_DEEMPH2); + + val = readl(qphy->base + PCIE20_PARF_PCS_DEEMPH3); + val &= ~0x3f; + val |= TX_DEEMPH_GEN1_VAL; + writel(val, qphy->base + PCIE20_PARF_PCS_DEEMPH3); + + /* Program Rx_Eq */ + val = readl(qphy->base + PCIE20_PARF_CONFIGBITS); + val &= ~0x7; + val |= PHY_RX0_EQ_GEN2_VAL; + writel(val, qphy->base + PCIE20_PARF_CONFIGBITS); + + /* Program Tx0_term_offset */ + val = readl(qphy->base + PCIE20_PARF_PHY_CTRL3); + val &= ~0x1f; + val |= PHY_TX0_TERM_OFFST_VAL; + writel(val, qphy->base + PCIE20_PARF_PHY_CTRL3); + + /* disable Tx2Rx Loopback */ + val = readl(qphy->base + PCIE20_PARF_PCS_CTRL); + val &= ~BIT(1); + writel(val, qphy->base + PCIE20_PARF_PCS_CTRL); + + /* De-assert Phy SW Reset */ + val = readl(qphy->base + PCIE2_PHY_RESET_CTRL); + val &= ~BIT(0); + writel(val, qphy->base + PCIE2_PHY_RESET_CTRL); + + usleep_range(1000, 2000); + + ret = reset_control_deassert(qphy->pipe_reset); + if (ret) { + dev_err(qphy->dev, "cannot deassert pipe reset\n"); + goto out; + } + + clk_set_rate(qphy->pipe_clk, 250000000); + + ret = clk_prepare_enable(qphy->pipe_clk); + if (ret) { + dev_err(qphy->dev, "failed to enable pipe clock\n"); + goto out; + } + + ret = readl_poll_timeout(qphy->base + PCIE20_PARF_PHY_STTS, val, + !(val & BIT(0)), 1000, 10); + if (ret) + dev_err(qphy->dev, "phy initialization failed\n"); + +out: + return ret; +} + +static int qcom_pcie2_phy_power_off(struct phy *phy) { + + return 0; +} + +static const struct phy_ops qcom_pcie2_ops = { + .power_on = qcom_pcie2_phy_power_on, + .power_off = qcom_pcie2_phy_power_off, + .owner = THIS_MODULE, +}; + +/* + * Register a fixed rate pipe clock. + * + * The _pipe_clksrc generated by PHY goes to the GCC that gate + * controls it. The _pipe_clk coming out of the GCC is requested + * by the PHY driver for its operations. + * We register the _pipe_clksrc here. The gcc driver takes care + * of assigning this _pipe_clksrc as parent to _pipe_clk. + * Below picture shows this relationship. + * + * +---------------+ + * | PHY block |<<---------------------------------------+ + * | | | + * | +-------+ | +-----+ | + * I/P---^-->| PLL |---^--->pipe_clksrc--->| GCC |--->pipe_clk---+ + * clk | +-------+ | +-----+ + * +---------------+ + */ +static int phy_pipe_clk_register(struct qcom_phy *qphy) { + struct device_node *np = qphy->dev->of_node; + struct clk_fixed_rate *fixed; + struct clk_init_data init = { }; + int ret; + + ret = of_property_read_string(np, "clock-output-names", &init.name); + if (ret) { + dev_err(qphy->dev, "%s: No clock-output-names\n", np->name); + return ret; + } + + fixed = devm_kzalloc(qphy->dev, sizeof(*fixed), GFP_KERNEL); + if (!fixed) + return -ENOMEM; + + init.ops = &clk_fixed_rate_ops; + + /* controllers using QMP phys use 125MHz pipe clock interface */ + fixed->fixed_rate = 250000000; + fixed->hw.init = &init; + + return devm_clk_hw_register(qphy->dev, &fixed->hw); +} + +static int qcom_pcie2_phy_probe(struct platform_device *pdev) { + struct phy_provider *phy_provider; + struct qcom_phy *qphy; + struct resource *res; + struct device *dev = &pdev->dev; + struct phy *phy; + int ret; + + qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL); + if (!qphy) + return -ENOMEM; + + qphy->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + qphy->base = devm_ioremap_resource(dev, res); + if (IS_ERR(qphy->base)) + return PTR_ERR(qphy->base); + + qphy->pipe_clk = devm_clk_get(dev, "pipe"); + if (IS_ERR(qphy->pipe_clk)) { + dev_err(dev, "unable to acquire pipe clock\n"); + return PTR_ERR(qphy->pipe_clk); + } + + phy = devm_phy_create(dev, dev->of_node, &qcom_pcie2_ops); + if (IS_ERR(phy)) { + dev_err(dev, "failed to create phy\n"); + return PTR_ERR(phy); + } + + phy_set_drvdata(phy, qphy); + + ret = phy_pipe_clk_register(qphy); + if (ret) { + dev_err(dev, "failed to register pipe_clk\n"); + return ret; + } + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(phy_provider)) + dev_err(dev, "failed to register phy provider\n"); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct of_device_id qcom_pcie2_phy_match_table[] = { + { .compatible = "qcom,pcie2-phy" }, + {} +}; + +MODULE_DEVICE_TABLE(of, qcom_pcie2_phy_match_table); + +static struct platform_driver qcom_pcie2_phy_driver = { + .probe = qcom_pcie2_phy_probe, + .driver = { + .name = "qcom-pcie2-phy", + .of_match_table = qcom_pcie2_phy_match_table, + }, +}; + +module_platform_driver(qcom_pcie2_phy_driver); +MODULE_DESCRIPTION("Qualcomm PCIe PHY driver"); +MODULE_LICENSE("GPL +v2"); diff --git a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v4.c b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v4.c index 885592078a853a4a0e2d1e6ebc07653b4b1fd70c..78eab289efb88215b686fd2a2ec69b7db37f360c 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v4.c +++ b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v4.c @@ -35,9 +35,19 @@ int ufs_qcom_phy_qmp_v4_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy, */ ufs_qcom_phy_write_tbl(ufs_qcom_phy, phy_cal_table_rate_A, ARRAY_SIZE(phy_cal_table_rate_A)); - if (ufs_qcom_phy->lanes_per_direction == 2) + if ((major == 0x4) && (minor == 0x001) && (step == 0x0000)) + ufs_qcom_phy_write_tbl(ufs_qcom_phy, phy_cal_table_rate_A_v2, + ARRAY_SIZE(phy_cal_table_rate_A_v2)); + + if (ufs_qcom_phy->lanes_per_direction == 2) { ufs_qcom_phy_write_tbl(ufs_qcom_phy, phy_cal_table_2nd_lane, ARRAY_SIZE(phy_cal_table_2nd_lane)); + if ((major == 0x4) && (minor == 0x001) && (step == 0x0000)) + ufs_qcom_phy_write_tbl(ufs_qcom_phy, + phy_cal_table_2nd_lane_v2, + ARRAY_SIZE(phy_cal_table_2nd_lane_v2)); + } + if (is_rate_B) ufs_qcom_phy_write_tbl(ufs_qcom_phy, phy_cal_table_rate_B, ARRAY_SIZE(phy_cal_table_rate_B)); diff --git a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v4.h b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v4.h index b998d776b336e83a8c82afd83a222cc24aef384f..24cd78889aade6a1dd1a006f3688de625c465373 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v4.h +++ b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-v4.h @@ -263,6 +263,16 @@ static struct ufs_qcom_phy_calibration phy_cal_table_rate_A[] = { UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_SO_GAIN, 0x04), }; +static struct ufs_qcom_phy_calibration phy_cal_table_rate_A_v2[] = { + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX0_LANE_MODE_1, 0x35), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_SO_SATURATION_AND_ENABLE, 0x5A), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_UCDR_FO_GAIN, 0x0E), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_MODE_00_LOW, 0x6D), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_MODE_00_HIGH, 0x6D), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_MODE_00_HIGH2, 0xED), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX0_RX_MODE_00_HIGH4, 0x3C), +}; + static struct ufs_qcom_phy_calibration phy_cal_table_2nd_lane[] = { UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX1_PWM_GEAR_1_DIVIDER_BAND0_1, 0x06), UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX1_PWM_GEAR_2_DIVIDER_BAND0_1, 0x03), @@ -307,6 +317,16 @@ static struct ufs_qcom_phy_calibration phy_cal_table_2nd_lane[] = { UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_SO_GAIN, 0x04), }; +static struct ufs_qcom_phy_calibration phy_cal_table_2nd_lane_v2[] = { + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX1_LANE_MODE_1, 0x35), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_SO_SATURATION_AND_ENABLE, 0x5A), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_FO_GAIN, 0x0E), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_MODE_00_LOW, 0x6D), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_MODE_00_HIGH, 0x6D), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_MODE_00_HIGH2, 0xED), + UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_MODE_00_HIGH4, 0x3C), +}; + static struct ufs_qcom_phy_calibration phy_cal_table_rate_B[] = { UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_MAP, 0x06), }; diff --git a/drivers/pinctrl/bcm/pinctrl-nsp-mux.c b/drivers/pinctrl/bcm/pinctrl-nsp-mux.c index 35c17653c694767c8e13d1a8d02d7d91718d23b3..87618a4e90e451f2834214a337ce81e12de560fc 100644 --- a/drivers/pinctrl/bcm/pinctrl-nsp-mux.c +++ b/drivers/pinctrl/bcm/pinctrl-nsp-mux.c @@ -460,8 +460,8 @@ static int nsp_pinmux_enable(struct pinctrl_dev *pctrl_dev, const struct nsp_pin_function *func; const struct nsp_pin_group *grp; - if (grp_select > pinctrl->num_groups || - func_select > pinctrl->num_functions) + if (grp_select >= pinctrl->num_groups || + func_select >= pinctrl->num_functions) return -EINVAL; func = &pinctrl->functions[func_select]; @@ -577,6 +577,8 @@ static int nsp_pinmux_probe(struct platform_device *pdev) return PTR_ERR(pinctrl->base0); res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) + return -EINVAL; pinctrl->base1 = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res)); if (!pinctrl->base1) { diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c index 6e472691d8eed6f0d3a71d20fe8e6e7e939d5b7d..17f2c5a505b25ee53a084c03d1d2c9afa5e82a44 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.c +++ b/drivers/pinctrl/freescale/pinctrl-imx.c @@ -389,7 +389,7 @@ static void imx_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, const char *name; int i, ret; - if (group > pctldev->num_groups) + if (group >= pctldev->num_groups) return; seq_printf(s, "\n"); diff --git a/drivers/pinctrl/freescale/pinctrl-imx1-core.c b/drivers/pinctrl/freescale/pinctrl-imx1-core.c index a4e9f430d45269c45367cacc1010087971c5596b..e2cca91fd2669c2953d13743279c21a852ddefd6 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx1-core.c +++ b/drivers/pinctrl/freescale/pinctrl-imx1-core.c @@ -433,7 +433,7 @@ static void imx1_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, const char *name; int i, ret; - if (group > info->ngroups) + if (group >= info->ngroups) return; seq_puts(s, "\n"); diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c index 433af328d9817a028f4bccce07492fbc6ac27a68..b78f42abff2f8a029c954e58e5ca518f3168ddd0 100644 --- a/drivers/pinctrl/pinctrl-amd.c +++ b/drivers/pinctrl/pinctrl-amd.c @@ -530,7 +530,8 @@ static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id) /* Each status bit covers four pins */ for (i = 0; i < 4; i++) { regval = readl(regs + i); - if (!(regval & PIN_IRQ_PENDING)) + if (!(regval & PIN_IRQ_PENDING) || + !(regval & BIT(INTERRUPT_MASK_OFF))) continue; irq = irq_find_mapping(gc->irqdomain, irqnr + i); generic_handle_irq(irq); diff --git a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl-ingenic.c index d84761822243ec4fb8716e0ecfed2859564ae291..103aaab41357033c1cc9a1e87bddda0cc376f4a7 100644 --- a/drivers/pinctrl/pinctrl-ingenic.c +++ b/drivers/pinctrl/pinctrl-ingenic.c @@ -536,7 +536,7 @@ static int ingenic_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, ingenic_config_pin(jzpc, pin, JZ4770_GPIO_PAT1, input); } else { ingenic_config_pin(jzpc, pin, JZ4740_GPIO_SELECT, false); - ingenic_config_pin(jzpc, pin, JZ4740_GPIO_DIR, input); + ingenic_config_pin(jzpc, pin, JZ4740_GPIO_DIR, !input); ingenic_config_pin(jzpc, pin, JZ4740_GPIO_FUNC, false); } diff --git a/drivers/pinctrl/pinctrl-rza1.c b/drivers/pinctrl/pinctrl-rza1.c index 04d058706b808fe8807192a6f3219c845cfa9b27..a865dc56a491b9b295f3d9cf6c409c4455b05e11 100644 --- a/drivers/pinctrl/pinctrl-rza1.c +++ b/drivers/pinctrl/pinctrl-rza1.c @@ -878,6 +878,7 @@ static int rza1_dt_node_to_map(struct pinctrl_dev *pctldev, const char *grpname; const char **fngrps; int ret, npins; + int gsel, fsel; npins = rza1_dt_node_pin_count(np); if (npins < 0) { @@ -927,18 +928,19 @@ static int rza1_dt_node_to_map(struct pinctrl_dev *pctldev, fngrps[0] = grpname; mutex_lock(&rza1_pctl->mutex); - ret = pinctrl_generic_add_group(pctldev, grpname, grpins, npins, - NULL); - if (ret) { + gsel = pinctrl_generic_add_group(pctldev, grpname, grpins, npins, + NULL); + if (gsel < 0) { mutex_unlock(&rza1_pctl->mutex); - return ret; + return gsel; } - ret = pinmux_generic_add_function(pctldev, grpname, fngrps, 1, - mux_confs); - if (ret) + fsel = pinmux_generic_add_function(pctldev, grpname, fngrps, 1, + mux_confs); + if (fsel < 0) { + ret = fsel; goto remove_group; - mutex_unlock(&rza1_pctl->mutex); + } dev_info(rza1_pctl->dev, "Parsed function and group %s with %d pins\n", grpname, npins); @@ -955,15 +957,15 @@ static int rza1_dt_node_to_map(struct pinctrl_dev *pctldev, (*map)->data.mux.group = np->name; (*map)->data.mux.function = np->name; *num_maps = 1; + mutex_unlock(&rza1_pctl->mutex); return 0; remove_function: - mutex_lock(&rza1_pctl->mutex); - pinmux_generic_remove_last_function(pctldev); + pinmux_generic_remove_function(pctldev, fsel); remove_group: - pinctrl_generic_remove_last_group(pctldev); + pinctrl_generic_remove_group(pctldev, gsel); mutex_unlock(&rza1_pctl->mutex); dev_info(rza1_pctl->dev, "Unable to parse function and group %s\n", diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index 82473d18075e15e354cbdddcdcf3866063c53ed9..bf52590588e56501cce6e2e8ce50810587ef4f06 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -189,6 +189,15 @@ config PINCTRL_SM6150 Qualcomm Technologies Inc TLMM block found on the Qualcomm Technologies Inc SM6150 platform. +config PINCTRL_TRINKET + tristate "Qualcomm Technologies Inc TRINKET pin controller driver" + depends on GPIOLIB && OF + select PINCTRL_MSM + help + This is the pinctrl, pinmux, pinconf and gpiolib driver for the + Qualcomm Technologies Inc TLMM block found on the Qualcomm + Technologies Inc TRINKET platform. + config PINCTRL_SDXPRAIRIE tristate "Qualcomm Technologies Inc SDXPRAIRIE pin controller driver" depends on GPIOLIB && OF diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index fe98640c1fbccb9b99a4e7b1d09abe478e11f775..0156e5619b9e2ea9100293635960e30190aeb588 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-mpp.o obj-$(CONFIG_PINCTRL_SM8150) += pinctrl-sm8150.o obj-$(CONFIG_PINCTRL_SDMSHRIKE) += pinctrl-sdmshrike.o obj-$(CONFIG_PINCTRL_SM6150) += pinctrl-sm6150.o +obj-$(CONFIG_PINCTRL_TRINKET) += pinctrl-trinket.o obj-$(CONFIG_PINCTRL_SDXPRAIRIE) += pinctrl-sdxprairie.o obj-$(CONFIG_PINCTRL_SDMMAGPIE) += pinctrl-sdmmagpie.o obj-$(CONFIG_PINCTRL_SLPI) += pinctrl-slpi.o diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index fef0970abaf24687ee60b252d61176ca14f38295..92ed7bada57c75de49105588c255f9ffd7f2275c 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "../core.h" #include "../pinconf.h" #include "pinctrl-msm.h" @@ -71,10 +72,13 @@ struct msm_pinctrl { const struct msm_pinctrl_soc_data *soc; void __iomem *regs; + void __iomem *pdc_regs; #ifdef CONFIG_FRAGMENTED_GPIO_ADDRESS_SPACE /* For holding per tile virtual address */ void __iomem *per_tile_regs[4]; #endif + phys_addr_t spi_cfg_regs; + phys_addr_t spi_cfg_end; }; static struct msm_pinctrl *msm_pinctrl_data; @@ -286,22 +290,30 @@ static int msm_config_group_get(struct pinctrl_dev *pctldev, /* Convert register value to pinconf value */ switch (param) { case PIN_CONFIG_BIAS_DISABLE: - arg = arg == MSM_NO_PULL; + if (arg != MSM_NO_PULL) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_BIAS_PULL_DOWN: - arg = arg == MSM_PULL_DOWN; + if (arg != MSM_PULL_DOWN) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_BIAS_BUS_HOLD: if (pctrl->soc->pull_no_keeper) return -ENOTSUPP; - arg = arg == MSM_KEEPER; + if (arg != MSM_KEEPER) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_BIAS_PULL_UP: if (pctrl->soc->pull_no_keeper) arg = arg == MSM_PULL_UP_NO_KEEPER; else arg = arg == MSM_PULL_UP; + if (!arg) + return -EINVAL; break; case PIN_CONFIG_DRIVE_STRENGTH: arg = msm_regval_to_drive(arg); @@ -975,6 +987,158 @@ static const struct irq_domain_ops msm_gpio_domain_ops = { .free = irq_domain_free_irqs_top, }; +static struct irq_chip msm_dirconn_irq_chip; + +static void msm_gpio_dirconn_handler(struct irq_desc *desc) +{ + struct irq_data *irqd = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); + + chained_irq_enter(chip, desc); + generic_handle_irq(irqd->irq); + chained_irq_exit(chip, desc); +} + +static void setup_pdc_gpio(struct irq_domain *domain, + unsigned int parent_irq, unsigned int gpio) +{ + int irq; + + if (gpio != 0) { + irq = irq_create_mapping(domain, gpio); + irq_set_parent(irq, parent_irq); + irq_set_chip(irq, &msm_dirconn_irq_chip); + irq_set_handler_data(parent_irq, irq_get_irq_data(irq)); + } + + __irq_set_handler(parent_irq, msm_gpio_dirconn_handler, false, NULL); +} + +static void request_dc_interrupt(struct irq_domain *domain, + struct irq_domain *parent, irq_hw_number_t hwirq, + unsigned int gpio) +{ + struct irq_fwspec fwspec; + unsigned int parent_irq; + + fwspec.fwnode = parent->fwnode; + fwspec.param[0] = 0; /* SPI */ + fwspec.param[1] = hwirq; + fwspec.param[2] = IRQ_TYPE_NONE; + fwspec.param_count = 3; + + parent_irq = irq_create_fwspec_mapping(&fwspec); + + setup_pdc_gpio(domain, parent_irq, gpio); +} + +/** + * gpio_muxed_to_pdc: Mux the GPIO to a PDC IRQ + * + * @pdc_domain: the PDC's domain + * @d: the GPIO's IRQ data + * + * Find a free PDC port for the GPIO and map the GPIO's mux information to the + * PDC registers; so the GPIO can be used a wakeup source. + */ +static void gpio_muxed_to_pdc(struct irq_domain *pdc_domain, struct irq_data *d) +{ + int i, j; + unsigned int mux; + struct irq_desc *desc = irq_data_to_desc(d); + struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + unsigned int gpio = d->hwirq; + struct msm_pinctrl *pctrl; + unsigned int irq; + + if (!gc || !parent_data) + return; + + pctrl = gpiochip_get_data(gc); + + for (i = 0; i < pctrl->soc->n_gpio_mux_in; i++) { + if (gpio != pctrl->soc->gpio_mux_in[i].gpio) + continue; + mux = pctrl->soc->gpio_mux_in[i].mux; + for (j = 0; j < pctrl->soc->n_pdc_mux_out; j++) { + struct msm_pdc_mux_output *pdc_out = + &pctrl->soc->pdc_mux_out[j]; + + if (pdc_out->mux == mux) + break; + if (pdc_out->mux) + continue; + pdc_out->mux = gpio; + irq = irq_find_mapping(pdc_domain, pdc_out->hwirq + 32); + /* setup the IRQ parent for the GPIO */ + setup_pdc_gpio(pctrl->chip.irqdomain, irq, gpio); + /* program pdc select grp register */ + writel_relaxed((mux & 0x3F), pctrl->pdc_regs + + (0x14 * j)); + break; + } + /* We have no more PDC port available */ + WARN_ON(j == pctrl->soc->n_pdc_mux_out); + } +} + +static bool is_gpio_tlmm_dc(struct irq_data *d, u32 type) +{ + const struct msm_pingroup *g; + unsigned long flags; + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct msm_pinctrl *pctrl; + bool ret = false; + unsigned int polarity = 0, offset, val; + int i; + void __iomem *base; + + if (!gc) + return false; + + pctrl = gpiochip_get_data(gc); + + for (i = 0; i < pctrl->soc->n_dir_conns; i++) { + struct msm_dir_conn *dir_conn = (struct msm_dir_conn *) + &pctrl->soc->dir_conn[i]; + + if (dir_conn->gpio == d->hwirq && dir_conn->tlmm_dc) { + ret = true; + offset = pctrl->soc->dir_conn_irq_base - + dir_conn->hwirq; + break; + } + } + + if (!ret) + return ret; + + if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)) + return ret; + + /* + * Since the default polarity is set to 0, change it to 1 for + * Rising edge and active high interrupt type such that the line + * is not inverted. + */ + polarity = 1; + + raw_spin_lock_irqsave(&pctrl->lock, flags); + + g = &pctrl->soc->groups[d->hwirq]; + base = reassign_pctrl_reg(pctrl->soc, d->hwirq); + + val = readl_relaxed(base + g->dir_conn_reg + (offset * 4)); + val |= polarity << 8; + + writel_relaxed(val, base + g->dir_conn_reg + (offset * 4)); + + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + + return ret; +} + static bool is_gpio_dual_edge(struct irq_data *d, irq_hw_number_t *dir_conn_irq) { struct irq_desc *desc = irq_data_to_desc(d); @@ -995,6 +1159,17 @@ static bool is_gpio_dual_edge(struct irq_data *d, irq_hw_number_t *dir_conn_irq) return true; } } + + for (i = 0; i < pctrl->soc->n_pdc_mux_out; i++) { + struct msm_pdc_mux_output *dir_conn = + &pctrl->soc->pdc_mux_out[i]; + + if (dir_conn->mux == d->hwirq && (dir_conn->hwirq + 32) + != parent_data->hwirq) { + *dir_conn_irq = dir_conn->hwirq + 32; + return true; + } + } return false; } @@ -1012,9 +1187,13 @@ static void msm_dirconn_irq_mask(struct irq_data *d) irq_get_irq_data(irq_find_mapping(parent_data->domain, dir_conn_irq)); - if (dir_conn_data && dir_conn_data->chip->irq_mask) + if (!dir_conn_data) + return; + + if (dir_conn_data->chip->irq_mask) dir_conn_data->chip->irq_mask(dir_conn_data); } + if (parent_data->chip->irq_mask) parent_data->chip->irq_mask(parent_data); } @@ -1065,7 +1244,10 @@ static void msm_dirconn_irq_unmask(struct irq_data *d) irq_get_irq_data(irq_find_mapping(parent_data->domain, dir_conn_irq)); - if (dir_conn_data && dir_conn_data->chip->irq_unmask) + if (!dir_conn_data) + return; + + if (dir_conn_data->chip->irq_unmask) dir_conn_data->chip->irq_unmask(dir_conn_data); } if (parent_data->chip->irq_unmask) @@ -1204,8 +1386,12 @@ static void add_dirconn_tlmm(struct irq_data *d, irq_hw_number_t irq) struct irq_desc *desc = irq_data_to_desc(d); struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq); struct irq_data *dir_conn_data = NULL; + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); int offset = 0; - unsigned int virt = 0; + unsigned int virt = 0, val = 0; + struct msm_pinctrl *pctrl; + phys_addr_t spi_cfg_reg = 0; + unsigned long flags; offset = select_dir_conn_mux(d, &irq); if (offset < 0 || !parent_data) @@ -1221,6 +1407,29 @@ static void add_dirconn_tlmm(struct irq_data *d, irq_hw_number_t irq) dir_conn_data = &(desc->irq_data); if (dir_conn_data) { + + pctrl = gpiochip_get_data(gc); + if (pctrl->spi_cfg_regs) { + spi_cfg_reg = pctrl->spi_cfg_regs + + ((dir_conn_data->hwirq - 32) / 32) * 4; + if (spi_cfg_reg < pctrl->spi_cfg_end) { + raw_spin_lock_irqsave(&pctrl->lock, flags); + val = scm_io_read(spi_cfg_reg); + /* + * Clear the respective bit for edge type + * interrupt + */ + val &= ~(1 << ((dir_conn_data->hwirq - 32) + % 32)); + WARN_ON(scm_io_write(spi_cfg_reg, val)); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + } else + pr_err("%s: type config failed for SPI: %lu\n", + __func__, irq); + } else + pr_debug("%s: type config for SPI is not supported\n", + __func__); + if (dir_conn_data->chip && dir_conn_data->chip->irq_set_type) dir_conn_data->chip->irq_set_type(dir_conn_data, IRQ_TYPE_EDGE_RISING); @@ -1259,23 +1468,54 @@ static int msm_dirconn_irq_set_type(struct irq_data *d, unsigned int type) { struct irq_desc *desc = irq_data_to_desc(d); struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); irq_hw_number_t irq = 0; + struct msm_pinctrl *pctrl; + phys_addr_t spi_cfg_reg = 0; + unsigned int config_val = 0; + unsigned int val = 0; + unsigned long flags; if (!parent_data) return 0; - if (type == IRQ_TYPE_EDGE_BOTH) { + pctrl = gpiochip_get_data(gc); + + if (type == IRQ_TYPE_EDGE_BOTH) add_dirconn_tlmm(d, irq); - } else { - if (is_gpio_dual_edge(d, &irq)) - remove_dirconn_tlmm(d, irq); - } + else if (is_gpio_dual_edge(d, &irq)) + remove_dirconn_tlmm(d, irq); + else if (is_gpio_tlmm_dc(d, type)) + type = IRQ_TYPE_EDGE_RISING; - if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) + + /* + * Shared SPI config for Edge is 0 and + * for Level interrupt is 1 + */ + if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) { irq_set_handler_locked(d, handle_level_irq); - else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) + config_val = 1; + } else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) irq_set_handler_locked(d, handle_edge_irq); + if (pctrl->spi_cfg_regs && type != IRQ_TYPE_NONE) { + spi_cfg_reg = pctrl->spi_cfg_regs + + ((parent_data->hwirq - 32) / 32) * 4; + if (spi_cfg_reg < pctrl->spi_cfg_end) { + raw_spin_lock_irqsave(&pctrl->lock, flags); + val = scm_io_read(spi_cfg_reg); + val &= ~(1 << ((parent_data->hwirq - 32) % 32)); + if (config_val) + val |= (1 << ((parent_data->hwirq - 32) % 32)); + WARN_ON(scm_io_write(spi_cfg_reg, val)); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); + } else + pr_err("%s: type config failed for SPI: %lu\n", + __func__, irq); + } else + pr_debug("%s: SPI type config is not supported\n", __func__); + if (parent_data->chip->irq_set_type) return parent_data->chip->irq_set_type(parent_data, type); @@ -1333,57 +1573,72 @@ static void msm_gpio_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } -static void msm_gpio_dirconn_handler(struct irq_desc *desc) -{ - struct irq_data *irqd = irq_desc_get_handler_data(desc); - struct irq_chip *chip = irq_desc_get_chip(desc); - - chained_irq_enter(chip, desc); - generic_handle_irq(irqd->irq); - chained_irq_exit(chip, desc); -} - static void msm_gpio_setup_dir_connects(struct msm_pinctrl *pctrl) { struct device_node *parent_node; - struct irq_domain *parent_domain; - struct irq_fwspec fwspec; + struct irq_domain *pdc_domain; unsigned int i; parent_node = of_irq_find_parent(pctrl->dev->of_node); - if (!parent_node) return; - parent_domain = irq_find_host(parent_node); - if (!parent_domain) + pdc_domain = irq_find_host(parent_node); + if (!pdc_domain) return; - fwspec.fwnode = parent_domain->fwnode; for (i = 0; i < pctrl->soc->n_dir_conns; i++) { const struct msm_dir_conn *dirconn = &pctrl->soc->dir_conn[i]; - unsigned int parent_irq; - int irq; - - fwspec.param[0] = 0; /* SPI */ - fwspec.param[1] = dirconn->hwirq; - fwspec.param[2] = IRQ_TYPE_NONE; - fwspec.param_count = 3; - parent_irq = irq_create_fwspec_mapping(&fwspec); - - if (dirconn->gpio != 0) { - irq = irq_create_mapping(pctrl->chip.irqdomain, - dirconn->gpio); - - irq_set_parent(irq, parent_irq); - irq_set_chip(irq, &msm_dirconn_irq_chip); - __irq_set_handler(parent_irq, msm_gpio_dirconn_handler, - false, NULL); - irq_set_handler_data(parent_irq, irq_get_irq_data(irq)); - } else { - __irq_set_handler(parent_irq, msm_gpio_dirconn_handler, - false, NULL); - } + struct irq_data *d; + + request_dc_interrupt(pctrl->chip.irqdomain, pdc_domain, + dirconn->hwirq, dirconn->gpio); + + if (!dirconn->gpio) + continue; + + if (!dirconn->tlmm_dc) + continue; + + /* + * If the gpio is routed through TLMM direct connect interrupts, + * program the TLMM registers for this setup. + */ + d = irq_get_irq_data(irq_find_mapping(pctrl->chip.irqdomain, + dirconn->gpio)); + if (!d) + continue; + + msm_dirconn_cfg_reg(d, pctrl->soc->dir_conn_irq_base + - (u32)dirconn->hwirq); + } + + for (i = 0; i < pctrl->soc->n_pdc_mux_out; i++) { + struct msm_pdc_mux_output *pdc_out = + &pctrl->soc->pdc_mux_out[i]; + + request_dc_interrupt(pctrl->chip.irqdomain, pdc_domain, + pdc_out->hwirq, 0); + } + + /* + * Statically choose the GPIOs for mapping to PDC. Dynamic mux mapping + * is very difficult. + */ + for (i = 0; i < pctrl->soc->n_gpio_mux_in; i++) { + unsigned int irq; + struct irq_data *d; + struct msm_gpio_mux_input *gpio_in = + &pctrl->soc->gpio_mux_in[i]; + if (!gpio_in->init) + continue; + + irq = irq_find_mapping(pctrl->chip.irqdomain, gpio_in->gpio); + d = irq_get_irq_data(irq); + if (!d) + continue; + + gpio_muxed_to_pdc(pdc_domain, d); } } @@ -1522,6 +1777,7 @@ int msm_pinctrl_probe(struct platform_device *pdev, struct msm_pinctrl *pctrl; struct resource *res; int ret; + char *key; msm_pinctrl_data = pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); @@ -1535,7 +1791,8 @@ int msm_pinctrl_probe(struct platform_device *pdev, raw_spin_lock_init(&pctrl->lock); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + key = "pinctrl"; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, key); pctrl->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(pctrl->regs)) return PTR_ERR(pctrl->regs); @@ -1554,6 +1811,17 @@ int msm_pinctrl_probe(struct platform_device *pdev, } #endif + key = "pdc"; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, key); + pctrl->pdc_regs = devm_ioremap_resource(&pdev->dev, res); + + key = "spi_cfg"; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, key); + if (res) { + pctrl->spi_cfg_regs = res->start; + pctrl->spi_cfg_end = res->end; + } + msm_pinctrl_setup_pm_reset(pctrl); pctrl->irq = platform_get_irq(pdev, 0); diff --git a/drivers/pinctrl/qcom/pinctrl-msm.h b/drivers/pinctrl/qcom/pinctrl-msm.h index 7050dc2cf0934d988ee0470d0e860a6b7789b739..6251b4d429a8f5619a9c7bc1b309641a29927500 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.h +++ b/drivers/pinctrl/qcom/pinctrl-msm.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2013, Sony Mobile Communications AB. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -104,16 +105,40 @@ struct msm_pingroup { unsigned intr_detection_bit:5; unsigned intr_detection_width:5; unsigned dir_conn_en_bit:8; -} +}; + +/** + * struct msm_gpio_mux_input - Map GPIO to Mux pin + * @mux:: The mux pin to which the GPIO is connected to + * @gpio: GPIO pin number + * @init: Setup PDC connection at probe + */ +struct msm_gpio_mux_input { + unsigned int mux; + unsigned int gpio; + bool init; +}; + +/** + * struct msm_pdc_mux_output - GPIO mux pin to PDC port + * @mux: GPIO mux pin number + * @hwirq: The PDC port (hwirq) that GPIO is connected to + */ +struct msm_pdc_mux_output { + unsigned int mux; + irq_hw_number_t hwirq; +}; /** * struct msm_dir_conn - Direct GPIO connect configuration * @gpio: GPIO pin number * @hwirq: The GIC interrupt that the pin is connected to - */; + * @tlmm_dc: indicates if the GPIO is routed to GIC directly + */ struct msm_dir_conn { unsigned int gpio; irq_hw_number_t hwirq; + bool tlmm_dc; }; /** @@ -129,6 +154,11 @@ struct msm_dir_conn { * @dir_conn: An array describing all the pins directly connected to GIC. * @ndirconns: The number of pins directly connected to GIC * @dir_conn_irq_base: Direct connect interrupt base register for kpss. + * @gpio_mux_in: Map of GPIO pin to the hwirq. + * @n_gpioc_mux_in: The number of entries in @pdc_mux_in. + * @pdc_mux_out: Map of GPIO mux to PDC port. + * @n_pdc_mux_out: The number of entries in @pdc_mux_out. + * @n_pdc_offset: The offset for the PDC mux pins */ struct msm_pinctrl_soc_data { const struct pinctrl_pin_desc *pins; @@ -142,6 +172,11 @@ struct msm_pinctrl_soc_data { const struct msm_dir_conn *dir_conn; unsigned int n_dir_conns; unsigned int dir_conn_irq_base; + struct msm_pdc_mux_output *pdc_mux_out; + unsigned int n_pdc_mux_out; + struct msm_gpio_mux_input *gpio_mux_in; + unsigned int n_gpio_mux_in; + unsigned int n_pdc_mux_offset; #ifdef CONFIG_FRAGMENTED_GPIO_ADDRESS_SPACE const u32 *tile_start; const u32 *tile_offsets; diff --git a/drivers/pinctrl/qcom/pinctrl-qcs405.c b/drivers/pinctrl/qcom/pinctrl-qcs405.c index 9299ff14956435700cfc73da4a8249944b2e5e81..833ed4c8398cca8ac1ba442115f0bed2b47ac295 100644 --- a/drivers/pinctrl/qcom/pinctrl-qcs405.c +++ b/drivers/pinctrl/qcom/pinctrl-qcs405.c @@ -422,7 +422,7 @@ static const unsigned int sdc2_data_pins[] = { 126 }; enum qcs405_functions { msm_mux_gpio, - msm_mux_hdmi_tx, + msm_mux_hdmi_cec, msm_mux_hdmi_ddc, msm_mux_blsp_uart_tx_a2, msm_mux_blsp_spi2, @@ -477,6 +477,7 @@ enum qcs405_functions { msm_mux_pwm_led11, msm_mux_i2s_3_data0_a, msm_mux_ebi2_lcd, + msm_mux_hdmi_hot, msm_mux_i2s_3_data1_a, msm_mux_i2s_3_data2_a, msm_mux_atest_char, @@ -631,7 +632,7 @@ static const char * const gpio_groups[] = { "gpio113", "gpio114", "gpio115", "gpio116", "gpio117", "gpio118", "gpio119", }; -static const char * const hdmi_tx_groups[] = { +static const char * const hdmi_cec_groups[] = { "gpio14", }; static const char * const hdmi_ddc_groups[] = { @@ -794,6 +795,9 @@ static const char * const blsp_i2c_scl_b2_groups[] = { static const char * const pwm_led11_groups[] = { "gpio43", }; +static const char * const hdmi_hot_groups[] = { + "gpio106", +}; static const char * const i2s_3_data0_a_groups[] = { "gpio106", }; @@ -1187,7 +1191,7 @@ static const char * const i2s_3_ws_a_groups[] = { static const struct msm_function qcs405_functions[] = { FUNCTION(gpio), - FUNCTION(hdmi_tx), + FUNCTION(hdmi_cec), FUNCTION(hdmi_ddc), FUNCTION(blsp_uart_tx_a2), FUNCTION(blsp_spi2), @@ -1240,6 +1244,7 @@ static const struct msm_function qcs405_functions[] = { FUNCTION(blsp_i2c_sda_b2), FUNCTION(blsp_i2c_scl_b2), FUNCTION(pwm_led11), + FUNCTION(hdmi_hot), FUNCTION(i2s_3_data0_a), FUNCTION(ebi2_lcd), FUNCTION(i2s_3_data1_a), @@ -1391,7 +1396,7 @@ static const struct msm_pingroup qcs405_groups[] = { [11] = PINGROUP(11, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), [12] = PINGROUP(12, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), [13] = PINGROUP(13, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), - [14] = PINGROUP(14, SOUTH, hdmi_tx, NA, NA, NA, NA, NA, NA, NA, NA), + [14] = PINGROUP(14, SOUTH, hdmi_cec, NA, NA, NA, NA, NA, NA, NA, NA), [15] = PINGROUP(15, SOUTH, hdmi_ddc, NA, NA, NA, NA, NA, NA, NA, NA), [16] = PINGROUP(16, SOUTH, hdmi_ddc, NA, NA, NA, NA, NA, NA, NA, NA), [17] = PINGROUP(17, NORTH, blsp_uart_tx_a2, blsp_spi2, m_voc, NA, NA, @@ -1554,8 +1559,8 @@ static const struct msm_pingroup qcs405_groups[] = { [104] = PINGROUP(104, EAST, i2s_3_sck_a, NA, NA, NA, NA, NA, NA, NA, NA), [105] = PINGROUP(105, EAST, i2s_3_ws_a, NA, NA, NA, NA, NA, NA, NA, NA), - [106] = PINGROUP(106, EAST, i2s_3_data0_a, ebi2_lcd, NA, NA, ebi_cdc, - NA, NA, NA, NA), + [106] = PINGROUP(106, EAST, i2s_3_data0_a, ebi2_lcd, hdmi_hot, NA, + ebi_cdc, NA, NA, NA, NA), [107] = PINGROUP(107, EAST, i2s_3_data1_a, ebi2_lcd, NA, NA, ebi_cdc, NA, NA, NA, NA), [108] = PINGROUP(108, EAST, i2s_3_data2_a, ebi2_lcd, atest_char, diff --git a/drivers/pinctrl/qcom/pinctrl-sdxprairie.c b/drivers/pinctrl/qcom/pinctrl-sdxprairie.c index df3765f213699c221c0f3941a74cb234c346e364..5aa2b918e0f7b48b886628400d18b65989ac997a 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdxprairie.c +++ b/drivers/pinctrl/qcom/pinctrl-sdxprairie.c @@ -50,6 +50,7 @@ .intr_cfg_reg = REG_BASE + 0x8 + REG_SIZE * id, \ .intr_status_reg = REG_BASE + 0xc + REG_SIZE * id, \ .intr_target_reg = REG_BASE + 0x8 + REG_SIZE * id, \ + .dir_conn_reg = REG_BASE + 0xad000,\ .mux_bit = 2, \ .pull_bit = 0, \ .drv_bit = 6, \ @@ -64,6 +65,7 @@ .intr_polarity_bit = 1, \ .intr_detection_bit = 2, \ .intr_detection_width = 2, \ + .dir_conn_en_bit = 8, \ } #define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \ @@ -1215,6 +1217,114 @@ static const struct msm_pingroup sdxprairie_groups[] = { [112] = UFS_RESET(ufs_reset, 0x0), }; +static struct msm_gpio_mux_input sdxprairie_mux_in[] = { + {0, 68}, + {1, 2}, + {2, 5}, + {3, 6}, + {4, 9}, + {5, 10}, + {6, 11}, + {7, 12}, + {8, 13}, + {9, 14}, + {10, 15}, + {11, 16}, + {12, 17}, + {13, 18}, + {14, 19}, + {15, 21}, + {16, 22}, + {17, 24}, + {18, 25}, + {19, 32}, + {20, 35}, + {21, 43}, + {22, 44}, + {23, 45}, + {24, 46}, + {25, 48}, + {26, 50}, + {27, 52}, + {28, 53}, + {29, 54}, + {30, 55}, + {31, 56}, + {32, 57}, + {33, 60}, + {34, 61}, + {35, 64}, + {37, 100}, + {38, 71}, + {39, 73}, + {40, 76}, + {41, 78}, + {42, 79}, + {43, 83}, + {44, 84}, + {45, 85}, + {46, 86}, + {47, 88}, + {48, 89}, + {49, 90, 1}, + {50, 23}, + {51, 93}, + {52, 94}, + {53, 95}, + {54, 96}, + {55, 99}, + {57, 77}, + {58, 103}, + {59, 104}, + {61, 65}, +}; + +static struct msm_pdc_mux_output sdxprairie_mux_out[] = { + {0, 167}, + {0, 168}, + {0, 169}, + {0, 170}, + {0, 171}, + {0, 172}, + {0, 173}, + {0, 174}, + {0, 175}, + {0, 176}, + {0, 177}, + {0, 178}, + {0, 179}, + {0, 180}, + {0, 181}, + {0, 182}, + {0, 183}, + {0, 184}, + {0, 185}, + {0, 186}, + {0, 187}, + {0, 188}, + {0, 189}, + {0, 190}, + {0, 191}, + {0, 192}, + {0, 193}, + {0, 194}, + {0, 195}, + {0, 196}, + {0, 197}, + {0, 198}, +}; + +static struct msm_dir_conn sdxprairie_dir_conn[] = { + {0, 220}, + {0, 219}, + {0, 218}, + {0, 217}, + {0, 216}, + {0, 215}, + {0, 214}, + {0, 213}, +}; + static const struct msm_pinctrl_soc_data sdxprairie_pinctrl = { .pins = sdxprairie_pins, .npins = ARRAY_SIZE(sdxprairie_pins), @@ -1223,6 +1333,14 @@ static const struct msm_pinctrl_soc_data sdxprairie_pinctrl = { .groups = sdxprairie_groups, .ngroups = ARRAY_SIZE(sdxprairie_groups), .ngpios = 108, + .gpio_mux_in = sdxprairie_mux_in, + .n_gpio_mux_in = ARRAY_SIZE(sdxprairie_mux_in), + .pdc_mux_out = sdxprairie_mux_out, + .n_pdc_mux_out = ARRAY_SIZE(sdxprairie_mux_out), + .n_pdc_mux_offset = 20, + .dir_conn_irq_base = 220, + .dir_conn = sdxprairie_dir_conn, + .n_dir_conns = ARRAY_SIZE(sdxprairie_dir_conn), }; static int sdxprairie_pinctrl_probe(struct platform_device *pdev) diff --git a/drivers/pinctrl/qcom/pinctrl-sm6150.c b/drivers/pinctrl/qcom/pinctrl-sm6150.c index 601384ee2174a49e35667efd82d00e0eb391cdb1..da15d91793f0d683b2dcd86558d7733ba20659da 100644 --- a/drivers/pinctrl/qcom/pinctrl-sm6150.c +++ b/drivers/pinctrl/qcom/pinctrl-sm6150.c @@ -474,7 +474,8 @@ enum sm6150_functions { msm_mux_qlink_request, msm_mux_qlink_enable, msm_mux_pa_indicator, - msm_mux_NAV_PPS, + msm_mux_NAV_PPS_IN, + msm_mux_NAV_PPS_OUT, msm_mux_GPS_TX, msm_mux_phase_flag23, msm_mux_GP_PDM0, @@ -587,20 +588,18 @@ static const char * const gpio_groups[] = { "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35", "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42", - "gpio43", "gpio44", "gpio45", "gpio45", "gpio46", "gpio47", "gpio48", - "gpio48", "gpio49", "gpio49", "gpio50", "gpio50", "gpio51", "gpio52", - "gpio53", "gpio54", "gpio55", "gpio56", "gpio57", "gpio58", "gpio59", - "gpio60", "gpio61", "gpio62", "gpio63", "gpio64", "gpio65", "gpio66", - "gpio67", "gpio68", "gpio69", "gpio70", "gpio71", "gpio72", "gpio73", - "gpio74", "gpio75", "gpio76", "gpio77", "gpio78", "gpio79", "gpio80", - "gpio81", "gpio82", "gpio83", "gpio84", "gpio84", "gpio85", "gpio86", - "gpio87", "gpio88", "gpio88", "gpio89", "gpio90", "gpio91", "gpio92", - "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98", "gpio98", - "gpio99", "gpio100", "gpio100", "gpio101", "gpio102", "gpio103", - "gpio104", "gpio105", "gpio106", "gpio107", "gpio108", "gpio109", - "gpio110", "gpio111", "gpio112", "gpio113", "gpio114", "gpio115", - "gpio116", "gpio117", "gpio118", "gpio119", "gpio120", "gpio121", - "gpio122", + "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49", + "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56", + "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63", + "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70", + "gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77", + "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84", + "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91", + "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98", + "gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104", + "gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110", + "gpio111", "gpio112", "gpio113", "gpio114", "gpio115", "gpio116", + "gpio117", "gpio118", "gpio119", "gpio120", "gpio121", "gpio122", }; static const char * const qdss_gpio6_groups[] = { "gpio0", "gpio30", @@ -845,9 +844,13 @@ static const char * const qlink_enable_groups[] = { static const char * const pa_indicator_groups[] = { "gpio53", }; -static const char * const NAV_PPS_groups[] = { - "gpio53", "gpio53", "gpio56", "gpio56", "gpio57", "gpio57", "gpio59", - "gpio59", "gpio60", "gpio60", +static const char * const NAV_PPS_IN_groups[] = { + "gpio53", "gpio56", "gpio57", "gpio59", + "gpio60", +}; +static const char * const NAV_PPS_OUT_groups[] = { + "gpio53", "gpio56", "gpio57", "gpio59", + "gpio60", }; static const char * const GPS_TX_groups[] = { "gpio53", "gpio54", "gpio56", "gpio57", "gpio59", "gpio60", @@ -1232,7 +1235,8 @@ static const struct msm_function sm6150_functions[] = { FUNCTION(qlink_request), FUNCTION(qlink_enable), FUNCTION(pa_indicator), - FUNCTION(NAV_PPS), + FUNCTION(NAV_PPS_IN), + FUNCTION(NAV_PPS_OUT), FUNCTION(GPS_TX), FUNCTION(phase_flag23), FUNCTION(GP_PDM0), @@ -1433,21 +1437,21 @@ static const struct msm_pingroup sm6150_groups[] = { NA), [52] = PINGROUP(52, SOUTH, qlink_enable, NA, NA, NA, NA, NA, NA, NA, NA), - [53] = PINGROUP(53, SOUTH, pa_indicator, NAV_PPS, NAV_PPS, GPS_TX, NA, - phase_flag23, NA, NA, NA), + [53] = PINGROUP(53, SOUTH, pa_indicator, NAV_PPS_IN, NAV_PPS_OUT, + GPS_TX, NA, phase_flag23, NA, NA, NA), [54] = PINGROUP(54, SOUTH, NA, GPS_TX, GP_PDM0, NA, phase_flag22, atest_usb13, ddr_pxi1, NA, NA), [55] = PINGROUP(55, SOUTH, NA, NA, phase_flag4, atest_usb12, ddr_pxi1, NA, NA, NA, NA), - [56] = PINGROUP(56, SOUTH, NA, NAV_PPS, NAV_PPS, GPS_TX, NA, NA, NA, - NA, NA), - [57] = PINGROUP(57, SOUTH, NA, NAV_PPS, GPS_TX, NAV_PPS, gcc_gp1, NA, - NA, NA, NA), + [56] = PINGROUP(56, SOUTH, NA, NAV_PPS_IN, NAV_PPS_OUT, GPS_TX, NA, + NA, NA, NA, NA), + [57] = PINGROUP(57, SOUTH, NA, NAV_PPS_IN, GPS_TX, NAV_PPS_OUT, + gcc_gp1, NA, NA, NA, NA), [58] = PINGROUP(58, SOUTH, NA, gcc_gp2, NA, NA, NA, NA, NA, NA, NA), - [59] = PINGROUP(59, SOUTH, NA, NAV_PPS, NAV_PPS, GPS_TX, gcc_gp3, NA, - NA, NA, NA), - [60] = PINGROUP(60, SOUTH, NA, NAV_PPS, NAV_PPS, GPS_TX, CRI_TRNG0, NA, - NA, NA, NA), + [59] = PINGROUP(59, SOUTH, NA, NAV_PPS_IN, NAV_PPS_OUT, GPS_TX, + gcc_gp3, NA, NA, NA, NA), + [60] = PINGROUP(60, SOUTH, NA, NAV_PPS_IN, NAV_PPS_OUT, GPS_TX, + CRI_TRNG0, NA, NA, NA, NA), [61] = PINGROUP(61, SOUTH, NA, CRI_TRNG, NA, NA, NA, NA, NA, NA, NA), [62] = PINGROUP(62, SOUTH, NA, CRI_TRNG1, NA, NA, NA, NA, NA, NA, NA), [63] = PINGROUP(63, SOUTH, NA, NA, GP_PDM2, NA, NA, NA, NA, NA, NA), diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c index 3bec5a41ca194845e658ee13c42b0269d50e7cd6..1b04e9adb957e42d0b921115cec2c6c5b263bf13 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c @@ -395,31 +395,47 @@ static int pmic_gpio_config_get(struct pinctrl_dev *pctldev, switch (param) { case PIN_CONFIG_DRIVE_PUSH_PULL: - arg = pad->buffer_type == PMIC_GPIO_OUT_BUF_CMOS; + if (pad->buffer_type != PMIC_GPIO_OUT_BUF_CMOS) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_DRIVE_OPEN_DRAIN: - arg = pad->buffer_type == PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS; + if (pad->buffer_type != PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_DRIVE_OPEN_SOURCE: - arg = pad->buffer_type == PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS; + if (pad->buffer_type != PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_BIAS_PULL_DOWN: - arg = pad->pullup == PMIC_GPIO_PULL_DOWN; + if (pad->pullup != PMIC_GPIO_PULL_DOWN) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_BIAS_DISABLE: - arg = pad->pullup = PMIC_GPIO_PULL_DISABLE; + if (pad->pullup != PMIC_GPIO_PULL_DISABLE) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_BIAS_PULL_UP: - arg = pad->pullup == PMIC_GPIO_PULL_UP_30; + if (pad->pullup != PMIC_GPIO_PULL_UP_30) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: - arg = !pad->is_enabled; + if (pad->is_enabled) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_POWER_SOURCE: arg = pad->power_source; break; case PIN_CONFIG_INPUT_ENABLE: - arg = pad->input_enabled; + if (!pad->input_enabled) + return -EINVAL; + arg = 1; break; case PIN_CONFIG_OUTPUT_ENABLE: arg = pad->output_enabled; diff --git a/drivers/pinctrl/qcom/pinctrl-trinket.c b/drivers/pinctrl/qcom/pinctrl-trinket.c new file mode 100644 index 0000000000000000000000000000000000000000..5ffd4af33c8087ffb032d14b2f4abd3b51fb1efd --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-trinket.c @@ -0,0 +1,1584 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +#include "pinctrl-msm.h" + +#define FUNCTION(fname) \ + [msm_mux_##fname] = { \ + .name = #fname, \ + .groups = fname##_groups, \ + .ngroups = ARRAY_SIZE(fname##_groups), \ + } + +#define NORTH +#define SOUTH 0x00500000 +#define WEST 0x00100000 +#define EAST 0x00900000 +#define DUMMY 0x0 +#define REG_SIZE 0x1000 +#define PINGROUP(id, base, f1, f2, f3, f4, f5, f6, f7, f8, f9) \ + { \ + .name = "gpio" #id, \ + .pins = gpio##id##_pins, \ + .npins = (unsigned int)ARRAY_SIZE(gpio##id##_pins), \ + .funcs = (int[]){ \ + msm_mux_gpio, /* gpio mode */ \ + msm_mux_##f1, \ + msm_mux_##f2, \ + msm_mux_##f3, \ + msm_mux_##f4, \ + msm_mux_##f5, \ + msm_mux_##f6, \ + msm_mux_##f7, \ + msm_mux_##f8, \ + msm_mux_##f9 \ + }, \ + .nfuncs = 10, \ + .ctl_reg = base + REG_SIZE * id, \ + .io_reg = base + 0x4 + REG_SIZE * id, \ + .intr_cfg_reg = base + 0x8 + REG_SIZE * id, \ + .intr_status_reg = base + 0xc + REG_SIZE * id, \ + .intr_target_reg = base + 0x8 + REG_SIZE * id, \ + .mux_bit = 2, \ + .pull_bit = 0, \ + .drv_bit = 6, \ + .oe_bit = 9, \ + .in_bit = 0, \ + .out_bit = 1, \ + .intr_enable_bit = 0, \ + .intr_status_bit = 0, \ + .intr_target_bit = 5, \ + .intr_target_kpss_val = 3, \ + .intr_raw_status_bit = 4, \ + .intr_polarity_bit = 1, \ + .intr_detection_bit = 2, \ + .intr_detection_width = 2, \ + } + +#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \ + { \ + .name = #pg_name, \ + .pins = pg_name##_pins, \ + .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins), \ + .ctl_reg = ctl, \ + .io_reg = 0, \ + .intr_cfg_reg = 0, \ + .intr_status_reg = 0, \ + .intr_target_reg = 0, \ + .mux_bit = -1, \ + .pull_bit = pull, \ + .drv_bit = drv, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = -1, \ + .intr_enable_bit = -1, \ + .intr_status_bit = -1, \ + .intr_target_bit = -1, \ + .intr_raw_status_bit = -1, \ + .intr_polarity_bit = -1, \ + .intr_detection_bit = -1, \ + .intr_detection_width = -1, \ + } + +#define UFS_RESET(pg_name, offset) \ + { \ + .name = #pg_name, \ + .pins = pg_name##_pins, \ + .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins), \ + .ctl_reg = offset, \ + .io_reg = offset + 0x4, \ + .intr_cfg_reg = 0, \ + .intr_status_reg = 0, \ + .intr_target_reg = 0, \ + .mux_bit = -1, \ + .pull_bit = 3, \ + .drv_bit = 0, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = 0, \ + .intr_enable_bit = -1, \ + .intr_status_bit = -1, \ + .intr_target_bit = -1, \ + .intr_raw_status_bit = -1, \ + .intr_polarity_bit = -1, \ + .intr_detection_bit = -1, \ + .intr_detection_width = -1, \ + } +static const struct pinctrl_pin_desc trinket_pins[] = { + PINCTRL_PIN(0, "GPIO_0"), + PINCTRL_PIN(1, "GPIO_1"), + PINCTRL_PIN(2, "GPIO_2"), + PINCTRL_PIN(3, "GPIO_3"), + PINCTRL_PIN(4, "GPIO_4"), + PINCTRL_PIN(5, "GPIO_5"), + PINCTRL_PIN(6, "GPIO_6"), + PINCTRL_PIN(7, "GPIO_7"), + PINCTRL_PIN(8, "GPIO_8"), + PINCTRL_PIN(9, "GPIO_9"), + PINCTRL_PIN(10, "GPIO_10"), + PINCTRL_PIN(11, "GPIO_11"), + PINCTRL_PIN(12, "GPIO_12"), + PINCTRL_PIN(13, "GPIO_13"), + PINCTRL_PIN(14, "GPIO_14"), + PINCTRL_PIN(15, "GPIO_15"), + PINCTRL_PIN(16, "GPIO_16"), + PINCTRL_PIN(17, "GPIO_17"), + PINCTRL_PIN(18, "GPIO_18"), + PINCTRL_PIN(19, "GPIO_19"), + PINCTRL_PIN(20, "GPIO_20"), + PINCTRL_PIN(21, "GPIO_21"), + PINCTRL_PIN(22, "GPIO_22"), + PINCTRL_PIN(23, "GPIO_23"), + PINCTRL_PIN(24, "GPIO_24"), + PINCTRL_PIN(25, "GPIO_25"), + PINCTRL_PIN(26, "GPIO_26"), + PINCTRL_PIN(27, "GPIO_27"), + PINCTRL_PIN(28, "GPIO_28"), + PINCTRL_PIN(29, "GPIO_29"), + PINCTRL_PIN(30, "GPIO_30"), + PINCTRL_PIN(31, "GPIO_31"), + PINCTRL_PIN(32, "GPIO_32"), + PINCTRL_PIN(33, "GPIO_33"), + PINCTRL_PIN(34, "GPIO_34"), + PINCTRL_PIN(35, "GPIO_35"), + PINCTRL_PIN(36, "GPIO_36"), + PINCTRL_PIN(37, "GPIO_37"), + PINCTRL_PIN(38, "GPIO_38"), + PINCTRL_PIN(39, "GPIO_39"), + PINCTRL_PIN(40, "GPIO_40"), + PINCTRL_PIN(41, "GPIO_41"), + PINCTRL_PIN(42, "GPIO_42"), + PINCTRL_PIN(43, "GPIO_43"), + PINCTRL_PIN(44, "GPIO_44"), + PINCTRL_PIN(45, "GPIO_45"), + PINCTRL_PIN(46, "GPIO_46"), + PINCTRL_PIN(47, "GPIO_47"), + PINCTRL_PIN(48, "GPIO_48"), + PINCTRL_PIN(49, "GPIO_49"), + PINCTRL_PIN(50, "GPIO_50"), + PINCTRL_PIN(51, "GPIO_51"), + PINCTRL_PIN(52, "GPIO_52"), + PINCTRL_PIN(53, "GPIO_53"), + PINCTRL_PIN(54, "GPIO_54"), + PINCTRL_PIN(55, "GPIO_55"), + PINCTRL_PIN(56, "GPIO_56"), + PINCTRL_PIN(57, "GPIO_57"), + PINCTRL_PIN(58, "GPIO_58"), + PINCTRL_PIN(59, "GPIO_59"), + PINCTRL_PIN(60, "GPIO_60"), + PINCTRL_PIN(61, "GPIO_61"), + PINCTRL_PIN(62, "GPIO_62"), + PINCTRL_PIN(63, "GPIO_63"), + PINCTRL_PIN(64, "GPIO_64"), + PINCTRL_PIN(65, "GPIO_65"), + PINCTRL_PIN(66, "GPIO_66"), + PINCTRL_PIN(67, "GPIO_67"), + PINCTRL_PIN(68, "GPIO_68"), + PINCTRL_PIN(69, "GPIO_69"), + PINCTRL_PIN(70, "GPIO_70"), + PINCTRL_PIN(71, "GPIO_71"), + PINCTRL_PIN(72, "GPIO_72"), + PINCTRL_PIN(73, "GPIO_73"), + PINCTRL_PIN(74, "GPIO_74"), + PINCTRL_PIN(75, "GPIO_75"), + PINCTRL_PIN(76, "GPIO_76"), + PINCTRL_PIN(77, "GPIO_77"), + PINCTRL_PIN(78, "GPIO_78"), + PINCTRL_PIN(79, "GPIO_79"), + PINCTRL_PIN(80, "GPIO_80"), + PINCTRL_PIN(81, "GPIO_81"), + PINCTRL_PIN(82, "GPIO_82"), + PINCTRL_PIN(83, "GPIO_83"), + PINCTRL_PIN(84, "GPIO_84"), + PINCTRL_PIN(85, "GPIO_85"), + PINCTRL_PIN(86, "GPIO_86"), + PINCTRL_PIN(87, "GPIO_87"), + PINCTRL_PIN(88, "GPIO_88"), + PINCTRL_PIN(89, "GPIO_89"), + PINCTRL_PIN(90, "GPIO_90"), + PINCTRL_PIN(91, "GPIO_91"), + PINCTRL_PIN(92, "GPIO_92"), + PINCTRL_PIN(93, "GPIO_93"), + PINCTRL_PIN(94, "GPIO_94"), + PINCTRL_PIN(95, "GPIO_95"), + PINCTRL_PIN(96, "GPIO_96"), + PINCTRL_PIN(97, "GPIO_97"), + PINCTRL_PIN(98, "GPIO_98"), + PINCTRL_PIN(99, "GPIO_99"), + PINCTRL_PIN(100, "GPIO_100"), + PINCTRL_PIN(101, "GPIO_101"), + PINCTRL_PIN(102, "GPIO_102"), + PINCTRL_PIN(103, "GPIO_103"), + PINCTRL_PIN(104, "GPIO_104"), + PINCTRL_PIN(105, "GPIO_105"), + PINCTRL_PIN(106, "GPIO_106"), + PINCTRL_PIN(107, "GPIO_107"), + PINCTRL_PIN(108, "GPIO_108"), + PINCTRL_PIN(109, "GPIO_109"), + PINCTRL_PIN(110, "GPIO_110"), + PINCTRL_PIN(111, "GPIO_111"), + PINCTRL_PIN(112, "GPIO_112"), + PINCTRL_PIN(113, "GPIO_113"), + PINCTRL_PIN(114, "GPIO_114"), + PINCTRL_PIN(115, "GPIO_115"), + PINCTRL_PIN(116, "GPIO_116"), + PINCTRL_PIN(117, "GPIO_117"), + PINCTRL_PIN(118, "GPIO_118"), + PINCTRL_PIN(119, "GPIO_119"), + PINCTRL_PIN(120, "GPIO_120"), + PINCTRL_PIN(121, "GPIO_121"), + PINCTRL_PIN(122, "GPIO_122"), + PINCTRL_PIN(123, "GPIO_123"), + PINCTRL_PIN(124, "GPIO_124"), + PINCTRL_PIN(125, "GPIO_125"), + PINCTRL_PIN(126, "GPIO_126"), + PINCTRL_PIN(127, "GPIO_127"), + PINCTRL_PIN(128, "GPIO_128"), + PINCTRL_PIN(129, "GPIO_129"), + PINCTRL_PIN(130, "GPIO_130"), + PINCTRL_PIN(131, "GPIO_131"), + PINCTRL_PIN(132, "GPIO_132"), + PINCTRL_PIN(133, "SDC1_RCLK"), + PINCTRL_PIN(134, "SDC1_CLK"), + PINCTRL_PIN(135, "SDC1_CMD"), + PINCTRL_PIN(136, "SDC1_DATA"), + PINCTRL_PIN(137, "SDC2_CLK"), + PINCTRL_PIN(138, "SDC2_CMD"), + PINCTRL_PIN(139, "SDC2_DATA"), + PINCTRL_PIN(140, "UFS_RESET"), +}; + +#define DECLARE_MSM_GPIO_PINS(pin) \ + static const unsigned int gpio##pin##_pins[] = { pin } +DECLARE_MSM_GPIO_PINS(0); +DECLARE_MSM_GPIO_PINS(1); +DECLARE_MSM_GPIO_PINS(2); +DECLARE_MSM_GPIO_PINS(3); +DECLARE_MSM_GPIO_PINS(4); +DECLARE_MSM_GPIO_PINS(5); +DECLARE_MSM_GPIO_PINS(6); +DECLARE_MSM_GPIO_PINS(7); +DECLARE_MSM_GPIO_PINS(8); +DECLARE_MSM_GPIO_PINS(9); +DECLARE_MSM_GPIO_PINS(10); +DECLARE_MSM_GPIO_PINS(11); +DECLARE_MSM_GPIO_PINS(12); +DECLARE_MSM_GPIO_PINS(13); +DECLARE_MSM_GPIO_PINS(14); +DECLARE_MSM_GPIO_PINS(15); +DECLARE_MSM_GPIO_PINS(16); +DECLARE_MSM_GPIO_PINS(17); +DECLARE_MSM_GPIO_PINS(18); +DECLARE_MSM_GPIO_PINS(19); +DECLARE_MSM_GPIO_PINS(20); +DECLARE_MSM_GPIO_PINS(21); +DECLARE_MSM_GPIO_PINS(22); +DECLARE_MSM_GPIO_PINS(23); +DECLARE_MSM_GPIO_PINS(24); +DECLARE_MSM_GPIO_PINS(25); +DECLARE_MSM_GPIO_PINS(26); +DECLARE_MSM_GPIO_PINS(27); +DECLARE_MSM_GPIO_PINS(28); +DECLARE_MSM_GPIO_PINS(29); +DECLARE_MSM_GPIO_PINS(30); +DECLARE_MSM_GPIO_PINS(31); +DECLARE_MSM_GPIO_PINS(32); +DECLARE_MSM_GPIO_PINS(33); +DECLARE_MSM_GPIO_PINS(34); +DECLARE_MSM_GPIO_PINS(35); +DECLARE_MSM_GPIO_PINS(36); +DECLARE_MSM_GPIO_PINS(37); +DECLARE_MSM_GPIO_PINS(38); +DECLARE_MSM_GPIO_PINS(39); +DECLARE_MSM_GPIO_PINS(40); +DECLARE_MSM_GPIO_PINS(41); +DECLARE_MSM_GPIO_PINS(42); +DECLARE_MSM_GPIO_PINS(43); +DECLARE_MSM_GPIO_PINS(44); +DECLARE_MSM_GPIO_PINS(45); +DECLARE_MSM_GPIO_PINS(46); +DECLARE_MSM_GPIO_PINS(47); +DECLARE_MSM_GPIO_PINS(48); +DECLARE_MSM_GPIO_PINS(49); +DECLARE_MSM_GPIO_PINS(50); +DECLARE_MSM_GPIO_PINS(51); +DECLARE_MSM_GPIO_PINS(52); +DECLARE_MSM_GPIO_PINS(53); +DECLARE_MSM_GPIO_PINS(54); +DECLARE_MSM_GPIO_PINS(55); +DECLARE_MSM_GPIO_PINS(56); +DECLARE_MSM_GPIO_PINS(57); +DECLARE_MSM_GPIO_PINS(58); +DECLARE_MSM_GPIO_PINS(59); +DECLARE_MSM_GPIO_PINS(60); +DECLARE_MSM_GPIO_PINS(61); +DECLARE_MSM_GPIO_PINS(62); +DECLARE_MSM_GPIO_PINS(63); +DECLARE_MSM_GPIO_PINS(64); +DECLARE_MSM_GPIO_PINS(65); +DECLARE_MSM_GPIO_PINS(66); +DECLARE_MSM_GPIO_PINS(67); +DECLARE_MSM_GPIO_PINS(68); +DECLARE_MSM_GPIO_PINS(69); +DECLARE_MSM_GPIO_PINS(70); +DECLARE_MSM_GPIO_PINS(71); +DECLARE_MSM_GPIO_PINS(72); +DECLARE_MSM_GPIO_PINS(73); +DECLARE_MSM_GPIO_PINS(74); +DECLARE_MSM_GPIO_PINS(75); +DECLARE_MSM_GPIO_PINS(76); +DECLARE_MSM_GPIO_PINS(77); +DECLARE_MSM_GPIO_PINS(78); +DECLARE_MSM_GPIO_PINS(79); +DECLARE_MSM_GPIO_PINS(80); +DECLARE_MSM_GPIO_PINS(81); +DECLARE_MSM_GPIO_PINS(82); +DECLARE_MSM_GPIO_PINS(83); +DECLARE_MSM_GPIO_PINS(84); +DECLARE_MSM_GPIO_PINS(85); +DECLARE_MSM_GPIO_PINS(86); +DECLARE_MSM_GPIO_PINS(87); +DECLARE_MSM_GPIO_PINS(88); +DECLARE_MSM_GPIO_PINS(89); +DECLARE_MSM_GPIO_PINS(90); +DECLARE_MSM_GPIO_PINS(91); +DECLARE_MSM_GPIO_PINS(92); +DECLARE_MSM_GPIO_PINS(93); +DECLARE_MSM_GPIO_PINS(94); +DECLARE_MSM_GPIO_PINS(95); +DECLARE_MSM_GPIO_PINS(96); +DECLARE_MSM_GPIO_PINS(97); +DECLARE_MSM_GPIO_PINS(98); +DECLARE_MSM_GPIO_PINS(99); +DECLARE_MSM_GPIO_PINS(100); +DECLARE_MSM_GPIO_PINS(101); +DECLARE_MSM_GPIO_PINS(102); +DECLARE_MSM_GPIO_PINS(103); +DECLARE_MSM_GPIO_PINS(104); +DECLARE_MSM_GPIO_PINS(105); +DECLARE_MSM_GPIO_PINS(106); +DECLARE_MSM_GPIO_PINS(107); +DECLARE_MSM_GPIO_PINS(108); +DECLARE_MSM_GPIO_PINS(109); +DECLARE_MSM_GPIO_PINS(110); +DECLARE_MSM_GPIO_PINS(111); +DECLARE_MSM_GPIO_PINS(112); +DECLARE_MSM_GPIO_PINS(113); +DECLARE_MSM_GPIO_PINS(114); +DECLARE_MSM_GPIO_PINS(115); +DECLARE_MSM_GPIO_PINS(116); +DECLARE_MSM_GPIO_PINS(117); +DECLARE_MSM_GPIO_PINS(118); +DECLARE_MSM_GPIO_PINS(119); +DECLARE_MSM_GPIO_PINS(120); +DECLARE_MSM_GPIO_PINS(121); +DECLARE_MSM_GPIO_PINS(122); +DECLARE_MSM_GPIO_PINS(123); +DECLARE_MSM_GPIO_PINS(124); +DECLARE_MSM_GPIO_PINS(125); +DECLARE_MSM_GPIO_PINS(126); +DECLARE_MSM_GPIO_PINS(127); +DECLARE_MSM_GPIO_PINS(128); +DECLARE_MSM_GPIO_PINS(129); +DECLARE_MSM_GPIO_PINS(130); +DECLARE_MSM_GPIO_PINS(131); +DECLARE_MSM_GPIO_PINS(132); + +static const unsigned int sdc1_rclk_pins[] = { 133 }; +static const unsigned int sdc1_clk_pins[] = { 134 }; +static const unsigned int sdc1_cmd_pins[] = { 135 }; +static const unsigned int sdc1_data_pins[] = { 136 }; +static const unsigned int sdc2_clk_pins[] = { 137 }; +static const unsigned int sdc2_cmd_pins[] = { 138 }; +static const unsigned int sdc2_data_pins[] = { 139 }; +static const unsigned int ufs_reset_pins[] = { 140 }; + +enum trinket_functions { + msm_mux_qup00, + msm_mux_gpio, + msm_mux_qdss_gpio6, + msm_mux_qdss_gpio7, + msm_mux_qdss_gpio8, + msm_mux_qdss_gpio9, + msm_mux_qup01, + msm_mux_qup02, + msm_mux_ddr_pxi0, + msm_mux_ddr_bist, + msm_mux_atest_tsens2, + msm_mux_vsense_trigger, + msm_mux_atest_usb1, + msm_mux_GP_PDM1, + msm_mux_phase_flag23, + msm_mux_dbg_out, + msm_mux_phase_flag28, + msm_mux_qup14, + msm_mux_atest_usb11, + msm_mux_ddr_pxi2, + msm_mux_atest_usb10, + msm_mux_JITTER_BIST, + msm_mux_ddr_pxi3, + msm_mux_pll_bypassnl, + msm_mux_PLL_BIST, + msm_mux_qup03, + msm_mux_pll_reset, + msm_mux_AGERA_PLL, + msm_mux_qdss_cti, + msm_mux_qup04, + msm_mux_wlan2_adc1, + msm_mux_wlan2_adc0, + msm_mux_WSA_CLK, + msm_mux_qup13, + msm_mux_ter_mi2s, + msm_mux_WSA_DATA, + msm_mux_qdss_gpio4, + msm_mux_qdss_gpio5, + msm_mux_qup10, + msm_mux_gcc_gp3, + msm_mux_phase_flag0, + msm_mux_phase_flag3, + msm_mux_phase_flag2, + msm_mux_phase_flag1, + msm_mux_qup12, + msm_mux_phase_flag15, + msm_mux_sd_write, + msm_mux_phase_flag29, + msm_mux_qup11, + msm_mux_phase_flag10, + msm_mux_cam_mclk, + msm_mux_atest_tsens, + msm_mux_cci_i2c, + msm_mux_qdss_gpio1, + msm_mux_cci_timer2, + msm_mux_cci_timer1, + msm_mux_gcc_gp2, + msm_mux_qdss_gpio2, + msm_mux_cci_async, + msm_mux_cci_timer4, + msm_mux_qdss_gpio12, + msm_mux_cci_timer0, + msm_mux_gcc_gp1, + msm_mux_qdss_gpio13, + msm_mux_cci_timer3, + msm_mux_qdss_gpio14, + msm_mux_qdss_gpio15, + msm_mux_wlan1_adc1, + msm_mux_qdss_gpio3, + msm_mux_wlan1_adc0, + msm_mux_qlink_request, + msm_mux_qlink_enable, + msm_mux_pa_indicator, + msm_mux_NAV_PPS, + msm_mux_GPS_TX, + msm_mux_GP_PDM0, + msm_mux_phase_flag22, + msm_mux_atest_usb13, + msm_mux_ddr_pxi1, + msm_mux_phase_flag4, + msm_mux_atest_usb12, + msm_mux_phase_flag9, + msm_mux_phase_flag8, + msm_mux_phase_flag7, + msm_mux_phase_flag27, + msm_mux_CRI_TRNG0, + msm_mux_phase_flag26, + msm_mux_CRI_TRNG, + msm_mux_phase_flag25, + msm_mux_CRI_TRNG1, + msm_mux_phase_flag6, + msm_mux_GP_PDM2, + msm_mux_phase_flag5, + msm_mux_SP_CMU, + msm_mux_atest_usb2, + msm_mux_atest_usb23, + msm_mux_uim2_data, + msm_mux_uim2_clk, + msm_mux_uim2_reset, + msm_mux_atest_usb22, + msm_mux_uim2_present, + msm_mux_atest_usb21, + msm_mux_uim1_data, + msm_mux_atest_usb20, + msm_mux_uim1_clk, + msm_mux_uim1_reset, + msm_mux_uim1_present, + msm_mux_mdp_vsync, + msm_mux_phase_flag17, + msm_mux_qdss_gpio0, + msm_mux_phase_flag13, + msm_mux_qdss_gpio, + msm_mux_phase_flag16, + msm_mux_phase_flag12, + msm_mux_phase_flag18, + msm_mux_qdss_gpio10, + msm_mux_copy_gp, + msm_mux_qdss_gpio11, + msm_mux_tsense_pwm, + msm_mux_mpm_pwr, + msm_mux_tgu_ch3, + msm_mux_phase_flag31, + msm_mux_mdp_vsync0, + msm_mux_mdp_vsync1, + msm_mux_mdp_vsync2, + msm_mux_mdp_vsync3, + msm_mux_mdp_vsync4, + msm_mux_mdp_vsync5, + msm_mux_tgu_ch0, + msm_mux_phase_flag11, + msm_mux_tgu_ch1, + msm_mux_atest_char1, + msm_mux_vfr_1, + msm_mux_tgu_ch2, + msm_mux_phase_flag30, + msm_mux_atest_char0, + msm_mux_phase_flag24, + msm_mux_atest_char2, + msm_mux_atest_char3, + msm_mux_ldo_en, + msm_mux_ldo_update, + msm_mux_phase_flag19, + msm_mux_prng_rosc, + msm_mux_dp_hot, + msm_mux_debug_hot, + msm_mux_COPY_PHASE, + msm_mux_usb_phy, + msm_mux_atest_char, + msm_mux_mss_lte, + msm_mux_swr_tx, + msm_mux_aud_sb, + msm_mux_qua_mi2s, + msm_mux_swr_rx, + msm_mux_edp_hot, + msm_mux_audio_ref, + msm_mux_pri_mi2s, + msm_mux_pri_mi2s_ws, + msm_mux_adsp_ext, + msm_mux_edp_lcd, + msm_mux_mclk2, + msm_mux_m_voc, + msm_mux_mclk1, + msm_mux_qca_sb, + msm_mux_qui_mi2s, + msm_mux_DMIC0_CLK, + msm_mux_sec_mi2s, + msm_mux_DMIC0_DATA, + msm_mux_DMIC1_CLK, + msm_mux_DMIC1_DATA, + msm_mux_phase_flag14, + msm_mux_phase_flag21, + msm_mux_phase_flag20, + msm_mux_NA, +}; + +static const char * const qup00_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", +}; +static const char * const gpio_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7", + "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14", + "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21", + "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", + "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35", + "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42", + "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49", + "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56", + "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63", + "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70", + "gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77", + "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84", + "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91", + "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98", + "gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104", + "gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110", + "gpio111", "gpio112", "gpio113", "gpio114", "gpio115", "gpio116", + "gpio117", "gpio118", "gpio119", "gpio120", "gpio121", "gpio122", + "gpio123", "gpio124", "gpio125", "gpio126", "gpio127", "gpio128", + "gpio129", "gpio130", "gpio131", "gpio132", +}; +static const char * const qdss_gpio6_groups[] = { + "gpio0", "gpio35", +}; +static const char * const qdss_gpio7_groups[] = { + "gpio1", "gpio36", +}; +static const char * const qdss_gpio8_groups[] = { + "gpio2", "gpio42", +}; +static const char * const qdss_gpio9_groups[] = { + "gpio3", "gpio83", +}; +static const char * const qup01_groups[] = { + "gpio4", "gpio5", +}; +static const char * const qup02_groups[] = { + "gpio6", "gpio7", "gpio8", "gpio9", +}; +static const char * const ddr_pxi0_groups[] = { + "gpio6", "gpio7", +}; +static const char * const ddr_bist_groups[] = { + "gpio7", "gpio8", "gpio9", "gpio10", +}; +static const char * const atest_tsens2_groups[] = { + "gpio7", +}; +static const char * const vsense_trigger_groups[] = { + "gpio7", +}; +static const char * const atest_usb1_groups[] = { + "gpio7", +}; +static const char * const GP_PDM1_groups[] = { + "gpio8", "gpio65", +}; +static const char * const phase_flag23_groups[] = { + "gpio8", +}; +static const char * const dbg_out_groups[] = { + "gpio9", +}; +static const char * const phase_flag28_groups[] = { + "gpio9", +}; +static const char * const qup14_groups[] = { + "gpio10", "gpio11", "gpio12", "gpio13", +}; +static const char * const atest_usb11_groups[] = { + "gpio10", +}; +static const char * const ddr_pxi2_groups[] = { + "gpio10", "gpio11", +}; +static const char * const atest_usb10_groups[] = { + "gpio11", +}; +static const char * const JITTER_BIST_groups[] = { + "gpio12", "gpio31", +}; +static const char * const ddr_pxi3_groups[] = { + "gpio12", "gpio13", +}; +static const char * const pll_bypassnl_groups[] = { + "gpio13", +}; +static const char * const PLL_BIST_groups[] = { + "gpio13", "gpio32", +}; +static const char * const qup03_groups[] = { + "gpio14", "gpio15", +}; +static const char * const pll_reset_groups[] = { + "gpio14", +}; +static const char * const AGERA_PLL_groups[] = { + "gpio14", "gpio33", +}; +static const char * const qdss_cti_groups[] = { + "gpio14", "gpio15", "gpio95", "gpio101", "gpio106", "gpio107", + "gpio110", "gpio111", +}; +static const char * const qup04_groups[] = { + "gpio16", "gpio17", +}; +static const char * const wlan2_adc1_groups[] = { + "gpio16", +}; +static const char * const wlan2_adc0_groups[] = { + "gpio17", +}; +static const char * const WSA_CLK_groups[] = { + "gpio18", +}; +static const char * const qup13_groups[] = { + "gpio18", "gpio19", "gpio20", "gpio21", +}; +static const char * const ter_mi2s_groups[] = { + "gpio18", "gpio19", "gpio20", "gpio21", +}; +static const char * const WSA_DATA_groups[] = { + "gpio19", +}; +static const char * const qdss_gpio4_groups[] = { + "gpio20", "gpio49", +}; +static const char * const qdss_gpio5_groups[] = { + "gpio21", "gpio34", +}; +static const char * const qup10_groups[] = { + "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", +}; +static const char * const gcc_gp3_groups[] = { + "gpio22", "gpio58", +}; +static const char * const phase_flag0_groups[] = { + "gpio23", +}; +static const char * const phase_flag3_groups[] = { + "gpio24", +}; +static const char * const phase_flag2_groups[] = { + "gpio25", +}; +static const char * const phase_flag1_groups[] = { + "gpio26", +}; +static const char * const qup12_groups[] = { + "gpio28", "gpio29", +}; +static const char * const phase_flag15_groups[] = { + "gpio28", +}; +static const char * const sd_write_groups[] = { + "gpio29", +}; +static const char * const phase_flag29_groups[] = { + "gpio29", +}; +static const char * const qup11_groups[] = { + "gpio30", "gpio31", "gpio32", "gpio33", +}; +static const char * const phase_flag10_groups[] = { + "gpio30", +}; +static const char * const cam_mclk_groups[] = { + "gpio34", "gpio35", "gpio36", +}; +static const char * const atest_tsens_groups[] = { + "gpio34", +}; +static const char * const cci_i2c_groups[] = { + "gpio37", "gpio38", "gpio39", "gpio40", +}; +static const char * const qdss_gpio1_groups[] = { + "gpio41", "gpio116", +}; +static const char * const cci_timer2_groups[] = { + "gpio42", +}; +static const char * const cci_timer1_groups[] = { + "gpio43", +}; +static const char * const gcc_gp2_groups[] = { + "gpio43", "gpio44", +}; +static const char * const qdss_gpio2_groups[] = { + "gpio43", "gpio117", +}; +static const char * const cci_async_groups[] = { + "gpio44", "gpio47", "gpio48", +}; +static const char * const cci_timer4_groups[] = { + "gpio44", +}; +static const char * const qdss_gpio12_groups[] = { + "gpio44", "gpio100", +}; +static const char * const cci_timer0_groups[] = { + "gpio45", +}; +static const char * const gcc_gp1_groups[] = { + "gpio45", "gpio46", +}; +static const char * const qdss_gpio13_groups[] = { + "gpio45", "gpio94", +}; +static const char * const cci_timer3_groups[] = { + "gpio46", +}; +static const char * const qdss_gpio14_groups[] = { + "gpio46", "gpio86", +}; +static const char * const qdss_gpio15_groups[] = { + "gpio47", "gpio96", +}; +static const char * const wlan1_adc1_groups[] = { + "gpio47", +}; +static const char * const qdss_gpio3_groups[] = { + "gpio48", "gpio118", +}; +static const char * const wlan1_adc0_groups[] = { + "gpio48", +}; +static const char * const qlink_request_groups[] = { + "gpio50", +}; +static const char * const qlink_enable_groups[] = { + "gpio51", +}; +static const char * const pa_indicator_groups[] = { + "gpio52", +}; +static const char * const NAV_PPS_groups[] = { + "gpio52", "gpio55", "gpio56", "gpio58", + "gpio59", +}; +static const char * const GPS_TX_groups[] = { + "gpio52", "gpio53", "gpio55", "gpio56", "gpio58", "gpio59", +}; +static const char * const GP_PDM0_groups[] = { + "gpio53", "gpio94", +}; +static const char * const phase_flag22_groups[] = { + "gpio53", +}; +static const char * const atest_usb13_groups[] = { + "gpio53", +}; +static const char * const ddr_pxi1_groups[] = { + "gpio53", "gpio54", +}; +static const char * const phase_flag4_groups[] = { + "gpio54", +}; +static const char * const atest_usb12_groups[] = { + "gpio54", +}; +static const char * const phase_flag9_groups[] = { + "gpio55", +}; +static const char * const phase_flag8_groups[] = { + "gpio56", +}; +static const char * const phase_flag7_groups[] = { + "gpio57", +}; +static const char * const phase_flag27_groups[] = { + "gpio58", +}; +static const char * const CRI_TRNG0_groups[] = { + "gpio59", +}; +static const char * const phase_flag26_groups[] = { + "gpio59", +}; +static const char * const CRI_TRNG_groups[] = { + "gpio60", +}; +static const char * const phase_flag25_groups[] = { + "gpio60", +}; +static const char * const CRI_TRNG1_groups[] = { + "gpio61", +}; +static const char * const phase_flag6_groups[] = { + "gpio61", +}; +static const char * const GP_PDM2_groups[] = { + "gpio62", "gpio78", +}; +static const char * const phase_flag5_groups[] = { + "gpio62", +}; +static const char * const SP_CMU_groups[] = { + "gpio63", +}; +static const char * const atest_usb2_groups[] = { + "gpio66", +}; +static const char * const atest_usb23_groups[] = { + "gpio67", +}; +static const char * const uim2_data_groups[] = { + "gpio72", +}; +static const char * const uim2_clk_groups[] = { + "gpio73", +}; +static const char * const uim2_reset_groups[] = { + "gpio74", +}; +static const char * const atest_usb22_groups[] = { + "gpio74", +}; +static const char * const uim2_present_groups[] = { + "gpio75", +}; +static const char * const atest_usb21_groups[] = { + "gpio75", +}; +static const char * const uim1_data_groups[] = { + "gpio76", +}; +static const char * const atest_usb20_groups[] = { + "gpio76", +}; +static const char * const uim1_clk_groups[] = { + "gpio77", +}; +static const char * const uim1_reset_groups[] = { + "gpio78", +}; +static const char * const uim1_present_groups[] = { + "gpio79", +}; +static const char * const mdp_vsync_groups[] = { + "gpio80", "gpio81", "gpio82", "gpio89", "gpio96", "gpio97", +}; +static const char * const phase_flag17_groups[] = { + "gpio80", +}; +static const char * const qdss_gpio0_groups[] = { + "gpio80", "gpio115", +}; +static const char * const phase_flag13_groups[] = { + "gpio81", +}; +static const char * const qdss_gpio_groups[] = { + "gpio81", "gpio82", "gpio102", "gpio114", +}; +static const char * const phase_flag16_groups[] = { + "gpio82", +}; +static const char * const phase_flag12_groups[] = { + "gpio83", +}; +static const char * const phase_flag18_groups[] = { + "gpio84", +}; +static const char * const qdss_gpio10_groups[] = { + "gpio84", "gpio91", +}; +static const char * const copy_gp_groups[] = { + "gpio85", +}; +static const char * const qdss_gpio11_groups[] = { + "gpio85", "gpio92", +}; +static const char * const tsense_pwm_groups[] = { + "gpio87", +}; +static const char * const mpm_pwr_groups[] = { + "gpio88", +}; +static const char * const tgu_ch3_groups[] = { + "gpio88", +}; +static const char * const phase_flag31_groups[] = { + "gpio88", +}; +static const char * const mdp_vsync0_groups[] = { + "gpio89", +}; +static const char * const mdp_vsync1_groups[] = { + "gpio89", +}; +static const char * const mdp_vsync2_groups[] = { + "gpio89", +}; +static const char * const mdp_vsync3_groups[] = { + "gpio89", +}; +static const char * const mdp_vsync4_groups[] = { + "gpio89", +}; +static const char * const mdp_vsync5_groups[] = { + "gpio89", +}; +static const char * const tgu_ch0_groups[] = { + "gpio89", +}; +static const char * const phase_flag11_groups[] = { + "gpio89", +}; +static const char * const tgu_ch1_groups[] = { + "gpio90", +}; +static const char * const atest_char1_groups[] = { + "gpio90", +}; +static const char * const vfr_1_groups[] = { + "gpio91", +}; +static const char * const tgu_ch2_groups[] = { + "gpio91", +}; +static const char * const phase_flag30_groups[] = { + "gpio91", +}; +static const char * const atest_char0_groups[] = { + "gpio92", +}; +static const char * const phase_flag24_groups[] = { + "gpio93", +}; +static const char * const atest_char2_groups[] = { + "gpio93", +}; +static const char * const atest_char3_groups[] = { + "gpio94", +}; +static const char * const ldo_en_groups[] = { + "gpio96", +}; +static const char * const ldo_update_groups[] = { + "gpio97", +}; +static const char * const phase_flag19_groups[] = { + "gpio98", +}; +static const char * const prng_rosc_groups[] = { + "gpio98", "gpio100", +}; +static const char * const dp_hot_groups[] = { + "gpio100", +}; +static const char * const debug_hot_groups[] = { + "gpio101", +}; +static const char * const COPY_PHASE_groups[] = { + "gpio101", +}; +static const char * const usb_phy_groups[] = { + "gpio102", +}; +static const char * const atest_char_groups[] = { + "gpio102", +}; +static const char * const mss_lte_groups[] = { + "gpio104", "gpio105", +}; +static const char * const swr_tx_groups[] = { + "gpio106", "gpio107", "gpio108", "gpio109", +}; +static const char * const aud_sb_groups[] = { + "gpio106", "gpio107", "gpio108", "gpio109", +}; +static const char * const qua_mi2s_groups[] = { + "gpio106", "gpio107", "gpio108", "gpio109", "gpio110", "gpio111", +}; +static const char * const swr_rx_groups[] = { + "gpio110", "gpio111", "gpio112", +}; +static const char * const edp_hot_groups[] = { + "gpio111", +}; +static const char * const audio_ref_groups[] = { + "gpio112", +}; +static const char * const pri_mi2s_groups[] = { + "gpio113", "gpio115", "gpio116", +}; +static const char * const pri_mi2s_ws_groups[] = { + "gpio114", +}; +static const char * const adsp_ext_groups[] = { + "gpio116", +}; +static const char * const edp_lcd_groups[] = { + "gpio117", +}; +static const char * const mclk2_groups[] = { + "gpio118", +}; +static const char * const m_voc_groups[] = { + "gpio118", +}; +static const char * const mclk1_groups[] = { + "gpio119", +}; +static const char * const qca_sb_groups[] = { + "gpio121", "gpio122", +}; +static const char * const qui_mi2s_groups[] = { + "gpio121", "gpio122", "gpio123", "gpio124", +}; +static const char * const DMIC0_CLK_groups[] = { + "gpio125", +}; +static const char * const sec_mi2s_groups[] = { + "gpio125", "gpio126", "gpio127", "gpio128", +}; +static const char * const DMIC0_DATA_groups[] = { + "gpio126", +}; +static const char * const DMIC1_CLK_groups[] = { + "gpio127", +}; +static const char * const DMIC1_DATA_groups[] = { + "gpio128", +}; +static const char * const phase_flag14_groups[] = { + "gpio129", +}; +static const char * const phase_flag21_groups[] = { + "gpio130", +}; +static const char * const phase_flag20_groups[] = { + "gpio131", +}; + +static const struct msm_function trinket_functions[] = { + FUNCTION(qup00), + FUNCTION(gpio), + FUNCTION(qdss_gpio6), + FUNCTION(qdss_gpio7), + FUNCTION(qdss_gpio8), + FUNCTION(qdss_gpio9), + FUNCTION(qup01), + FUNCTION(qup02), + FUNCTION(ddr_pxi0), + FUNCTION(ddr_bist), + FUNCTION(atest_tsens2), + FUNCTION(vsense_trigger), + FUNCTION(atest_usb1), + FUNCTION(GP_PDM1), + FUNCTION(phase_flag23), + FUNCTION(dbg_out), + FUNCTION(phase_flag28), + FUNCTION(qup14), + FUNCTION(atest_usb11), + FUNCTION(ddr_pxi2), + FUNCTION(atest_usb10), + FUNCTION(JITTER_BIST), + FUNCTION(ddr_pxi3), + FUNCTION(pll_bypassnl), + FUNCTION(PLL_BIST), + FUNCTION(qup03), + FUNCTION(pll_reset), + FUNCTION(AGERA_PLL), + FUNCTION(qdss_cti), + FUNCTION(qup04), + FUNCTION(wlan2_adc1), + FUNCTION(wlan2_adc0), + FUNCTION(WSA_CLK), + FUNCTION(qup13), + FUNCTION(ter_mi2s), + FUNCTION(WSA_DATA), + FUNCTION(qdss_gpio4), + FUNCTION(qdss_gpio5), + FUNCTION(qup10), + FUNCTION(gcc_gp3), + FUNCTION(phase_flag0), + FUNCTION(phase_flag3), + FUNCTION(phase_flag2), + FUNCTION(phase_flag1), + FUNCTION(qup12), + FUNCTION(phase_flag15), + FUNCTION(sd_write), + FUNCTION(phase_flag29), + FUNCTION(qup11), + FUNCTION(phase_flag10), + FUNCTION(cam_mclk), + FUNCTION(atest_tsens), + FUNCTION(cci_i2c), + FUNCTION(qdss_gpio1), + FUNCTION(cci_timer2), + FUNCTION(cci_timer1), + FUNCTION(gcc_gp2), + FUNCTION(qdss_gpio2), + FUNCTION(cci_async), + FUNCTION(cci_timer4), + FUNCTION(qdss_gpio12), + FUNCTION(cci_timer0), + FUNCTION(gcc_gp1), + FUNCTION(qdss_gpio13), + FUNCTION(cci_timer3), + FUNCTION(qdss_gpio14), + FUNCTION(qdss_gpio15), + FUNCTION(wlan1_adc1), + FUNCTION(qdss_gpio3), + FUNCTION(wlan1_adc0), + FUNCTION(qlink_request), + FUNCTION(qlink_enable), + FUNCTION(pa_indicator), + FUNCTION(NAV_PPS), + FUNCTION(GPS_TX), + FUNCTION(GP_PDM0), + FUNCTION(phase_flag22), + FUNCTION(atest_usb13), + FUNCTION(ddr_pxi1), + FUNCTION(phase_flag4), + FUNCTION(atest_usb12), + FUNCTION(phase_flag9), + FUNCTION(phase_flag8), + FUNCTION(phase_flag7), + FUNCTION(phase_flag27), + FUNCTION(CRI_TRNG0), + FUNCTION(phase_flag26), + FUNCTION(CRI_TRNG), + FUNCTION(phase_flag25), + FUNCTION(CRI_TRNG1), + FUNCTION(phase_flag6), + FUNCTION(GP_PDM2), + FUNCTION(phase_flag5), + FUNCTION(SP_CMU), + FUNCTION(atest_usb2), + FUNCTION(atest_usb23), + FUNCTION(uim2_data), + FUNCTION(uim2_clk), + FUNCTION(uim2_reset), + FUNCTION(atest_usb22), + FUNCTION(uim2_present), + FUNCTION(atest_usb21), + FUNCTION(uim1_data), + FUNCTION(atest_usb20), + FUNCTION(uim1_clk), + FUNCTION(uim1_reset), + FUNCTION(uim1_present), + FUNCTION(mdp_vsync), + FUNCTION(phase_flag17), + FUNCTION(qdss_gpio0), + FUNCTION(phase_flag13), + FUNCTION(qdss_gpio), + FUNCTION(phase_flag16), + FUNCTION(phase_flag12), + FUNCTION(phase_flag18), + FUNCTION(qdss_gpio10), + FUNCTION(copy_gp), + FUNCTION(qdss_gpio11), + FUNCTION(tsense_pwm), + FUNCTION(mpm_pwr), + FUNCTION(tgu_ch3), + FUNCTION(phase_flag31), + FUNCTION(mdp_vsync0), + FUNCTION(mdp_vsync1), + FUNCTION(mdp_vsync2), + FUNCTION(mdp_vsync3), + FUNCTION(mdp_vsync4), + FUNCTION(mdp_vsync5), + FUNCTION(tgu_ch0), + FUNCTION(phase_flag11), + FUNCTION(tgu_ch1), + FUNCTION(atest_char1), + FUNCTION(vfr_1), + FUNCTION(tgu_ch2), + FUNCTION(phase_flag30), + FUNCTION(atest_char0), + FUNCTION(phase_flag24), + FUNCTION(atest_char2), + FUNCTION(atest_char3), + FUNCTION(ldo_en), + FUNCTION(ldo_update), + FUNCTION(phase_flag19), + FUNCTION(prng_rosc), + FUNCTION(dp_hot), + FUNCTION(debug_hot), + FUNCTION(COPY_PHASE), + FUNCTION(usb_phy), + FUNCTION(atest_char), + FUNCTION(mss_lte), + FUNCTION(swr_tx), + FUNCTION(aud_sb), + FUNCTION(qua_mi2s), + FUNCTION(swr_rx), + FUNCTION(edp_hot), + FUNCTION(audio_ref), + FUNCTION(pri_mi2s), + FUNCTION(pri_mi2s_ws), + FUNCTION(adsp_ext), + FUNCTION(edp_lcd), + FUNCTION(mclk2), + FUNCTION(m_voc), + FUNCTION(mclk1), + FUNCTION(qca_sb), + FUNCTION(qui_mi2s), + FUNCTION(DMIC0_CLK), + FUNCTION(sec_mi2s), + FUNCTION(DMIC0_DATA), + FUNCTION(DMIC1_CLK), + FUNCTION(DMIC1_DATA), + FUNCTION(phase_flag14), + FUNCTION(phase_flag21), + FUNCTION(phase_flag20), +}; + +/* Every pin is maintained as a single group, and missing or non-existing pin + * would be maintained as dummy group to synchronize pin group index with + * pin descriptor registered with pinctrl core. + * Clients would not be able to request these dummy pin groups. + */ +static const struct msm_pingroup trinket_groups[] = { + [0] = PINGROUP(0, WEST, qup00, NA, qdss_gpio6, NA, NA, NA, NA, NA, NA), + [1] = PINGROUP(1, WEST, qup00, NA, qdss_gpio7, NA, NA, NA, NA, NA, NA), + [2] = PINGROUP(2, WEST, qup00, NA, qdss_gpio8, NA, NA, NA, NA, NA, NA), + [3] = PINGROUP(3, WEST, qup00, NA, qdss_gpio9, NA, NA, NA, NA, NA, NA), + [4] = PINGROUP(4, WEST, qup01, NA, NA, NA, NA, NA, NA, NA, NA), + [5] = PINGROUP(5, WEST, qup01, NA, NA, NA, NA, NA, NA, NA, NA), + [6] = PINGROUP(6, WEST, qup02, ddr_pxi0, NA, NA, NA, NA, NA, NA, NA), + [7] = PINGROUP(7, WEST, qup02, ddr_bist, atest_tsens2, vsense_trigger, + atest_usb1, ddr_pxi0, NA, NA, NA), + [8] = PINGROUP(8, WEST, qup02, GP_PDM1, ddr_bist, NA, phase_flag23, NA, + NA, NA, NA), + [9] = PINGROUP(9, WEST, qup02, ddr_bist, dbg_out, phase_flag28, NA, NA, + NA, NA, NA), + [10] = PINGROUP(10, EAST, qup14, ddr_bist, atest_usb11, ddr_pxi2, NA, + NA, NA, NA, NA), + [11] = PINGROUP(11, EAST, qup14, atest_usb10, ddr_pxi2, NA, NA, NA, NA, + NA, NA), + [12] = PINGROUP(12, EAST, qup14, JITTER_BIST, ddr_pxi3, NA, NA, NA, NA, + NA, NA), + [13] = PINGROUP(13, EAST, qup14, pll_bypassnl, PLL_BIST, NA, ddr_pxi3, + NA, NA, NA, NA), + [14] = PINGROUP(14, WEST, qup03, qup03, pll_reset, AGERA_PLL, NA, + qdss_cti, NA, NA, NA), + [15] = PINGROUP(15, WEST, qup03, qup03, qdss_cti, NA, NA, NA, NA, NA, + NA), + [16] = PINGROUP(16, WEST, qup04, qup04, NA, wlan2_adc1, NA, NA, NA, NA, + NA), + [17] = PINGROUP(17, WEST, qup04, qup04, NA, wlan2_adc0, NA, NA, NA, NA, + NA), + [18] = PINGROUP(18, EAST, WSA_CLK, qup13, ter_mi2s, NA, NA, NA, NA, NA, + NA), + [19] = PINGROUP(19, EAST, WSA_DATA, qup13, ter_mi2s, NA, NA, NA, NA, + NA, NA), + [20] = PINGROUP(20, EAST, qup13, ter_mi2s, qdss_gpio4, NA, NA, NA, NA, + NA, NA), + [21] = PINGROUP(21, EAST, qup13, ter_mi2s, NA, qdss_gpio5, NA, NA, NA, + NA, NA), + [22] = PINGROUP(22, WEST, qup10, gcc_gp3, NA, NA, NA, NA, NA, NA, NA), + [23] = PINGROUP(23, WEST, qup10, NA, phase_flag0, NA, NA, NA, NA, NA, + NA), + [24] = PINGROUP(24, WEST, qup10, NA, phase_flag3, NA, NA, NA, NA, NA, + NA), + [25] = PINGROUP(25, WEST, qup10, NA, phase_flag2, NA, NA, NA, NA, NA, + NA), + [26] = PINGROUP(26, WEST, qup10, NA, phase_flag1, NA, NA, NA, NA, NA, + NA), + [27] = PINGROUP(27, WEST, qup10, NA, NA, NA, NA, NA, NA, NA, NA), + [28] = PINGROUP(28, WEST, qup12, NA, phase_flag15, NA, NA, NA, NA, NA, + NA), + [29] = PINGROUP(29, WEST, qup12, sd_write, NA, phase_flag29, NA, NA, + NA, NA, NA), + [30] = PINGROUP(30, WEST, qup11, NA, phase_flag10, NA, NA, NA, NA, NA, + NA), + [31] = PINGROUP(31, WEST, qup11, JITTER_BIST, NA, NA, NA, NA, NA, NA, + NA), + [32] = PINGROUP(32, WEST, qup11, PLL_BIST, NA, NA, NA, NA, NA, NA, NA), + [33] = PINGROUP(33, WEST, qup11, AGERA_PLL, NA, NA, NA, NA, NA, NA, NA), + [34] = PINGROUP(34, SOUTH, cam_mclk, NA, qdss_gpio5, atest_tsens, NA, + NA, NA, NA, NA), + [35] = PINGROUP(35, SOUTH, cam_mclk, NA, qdss_gpio6, NA, NA, NA, NA, + NA, NA), + [36] = PINGROUP(36, SOUTH, cam_mclk, NA, qdss_gpio7, NA, NA, NA, NA, + NA, NA), + [37] = PINGROUP(37, SOUTH, cci_i2c, NA, NA, NA, NA, NA, NA, NA, NA), + [38] = PINGROUP(38, EAST, cci_i2c, NA, NA, NA, NA, NA, NA, NA, NA), + [39] = PINGROUP(39, EAST, cci_i2c, NA, NA, NA, NA, NA, NA, NA, NA), + [40] = PINGROUP(40, EAST, cci_i2c, NA, NA, NA, NA, NA, NA, NA, NA), + [41] = PINGROUP(41, EAST, NA, qdss_gpio1, NA, NA, NA, NA, NA, NA, NA), + [42] = PINGROUP(42, EAST, cci_timer2, NA, qdss_gpio8, NA, NA, NA, NA, + NA, NA), + [43] = PINGROUP(43, EAST, cci_timer1, NA, gcc_gp2, NA, qdss_gpio2, NA, + NA, NA, NA), + [44] = PINGROUP(44, SOUTH, cci_async, cci_timer4, NA, gcc_gp2, NA, + qdss_gpio12, NA, NA, NA), + [45] = PINGROUP(45, SOUTH, cci_timer0, NA, gcc_gp1, qdss_gpio13, NA, + NA, NA, NA, NA), + [46] = PINGROUP(46, SOUTH, cci_timer3, NA, gcc_gp1, NA, qdss_gpio14, + NA, NA, NA, NA), + [47] = PINGROUP(47, SOUTH, cci_async, NA, qdss_gpio15, wlan1_adc1, NA, + NA, NA, NA, NA), + [48] = PINGROUP(48, SOUTH, cci_async, NA, qdss_gpio3, wlan1_adc0, NA, + NA, NA, NA, NA), + [49] = PINGROUP(49, SOUTH, qdss_gpio4, NA, NA, NA, NA, NA, NA, NA, NA), + [50] = PINGROUP(50, SOUTH, qlink_request, NA, NA, NA, NA, NA, NA, NA, + NA), + [51] = PINGROUP(51, SOUTH, qlink_enable, NA, NA, NA, NA, NA, NA, NA, + NA), + [52] = PINGROUP(52, SOUTH, pa_indicator, NAV_PPS, NAV_PPS, GPS_TX, NA, + NA, NA, NA, NA), + [53] = PINGROUP(53, SOUTH, NA, GPS_TX, GP_PDM0, NA, phase_flag22, + atest_usb13, ddr_pxi1, NA, NA), + [54] = PINGROUP(54, SOUTH, NA, NA, phase_flag4, atest_usb12, ddr_pxi1, + NA, NA, NA, NA), + [55] = PINGROUP(55, SOUTH, NA, NAV_PPS, NAV_PPS, GPS_TX, NA, + phase_flag9, NA, NA, NA), + [56] = PINGROUP(56, SOUTH, NA, NAV_PPS, GPS_TX, NAV_PPS, phase_flag8, + NA, NA, NA, NA), + [57] = PINGROUP(57, SOUTH, NA, phase_flag7, NA, NA, NA, NA, NA, NA, NA), + [58] = PINGROUP(58, SOUTH, NA, NAV_PPS, NAV_PPS, GPS_TX, gcc_gp3, NA, + phase_flag27, NA, NA), + [59] = PINGROUP(59, SOUTH, NA, NAV_PPS, NAV_PPS, GPS_TX, CRI_TRNG0, NA, + phase_flag26, NA, NA), + [60] = PINGROUP(60, SOUTH, NA, CRI_TRNG, NA, phase_flag25, NA, NA, NA, + NA, NA), + [61] = PINGROUP(61, SOUTH, NA, CRI_TRNG1, NA, phase_flag6, NA, NA, NA, + NA, NA), + [62] = PINGROUP(62, SOUTH, NA, NA, GP_PDM2, NA, phase_flag5, NA, NA, + NA, NA), + [63] = PINGROUP(63, SOUTH, NA, SP_CMU, NA, NA, NA, NA, NA, NA, NA), + [64] = PINGROUP(64, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [65] = PINGROUP(65, SOUTH, NA, GP_PDM1, NA, NA, NA, NA, NA, NA, NA), + [66] = PINGROUP(66, SOUTH, NA, NA, atest_usb2, NA, NA, NA, NA, NA, NA), + [67] = PINGROUP(67, SOUTH, NA, NA, atest_usb23, NA, NA, NA, NA, NA, NA), + [68] = PINGROUP(68, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [69] = PINGROUP(69, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [70] = PINGROUP(70, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [71] = PINGROUP(71, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [72] = PINGROUP(72, SOUTH, uim2_data, NA, NA, NA, NA, NA, NA, NA, NA), + [73] = PINGROUP(73, SOUTH, uim2_clk, NA, NA, NA, NA, NA, NA, NA, NA), + [74] = PINGROUP(74, SOUTH, uim2_reset, NA, atest_usb22, NA, NA, NA, NA, + NA, NA), + [75] = PINGROUP(75, SOUTH, uim2_present, NA, atest_usb21, NA, NA, NA, + NA, NA, NA), + [76] = PINGROUP(76, SOUTH, uim1_data, NA, atest_usb20, NA, NA, NA, NA, + NA, NA), + [77] = PINGROUP(77, SOUTH, uim1_clk, NA, NA, NA, NA, NA, NA, NA, NA), + [78] = PINGROUP(78, SOUTH, uim1_reset, GP_PDM2, NA, NA, NA, NA, NA, NA, + NA), + [79] = PINGROUP(79, SOUTH, uim1_present, NA, NA, NA, NA, NA, NA, NA, + NA), + [80] = PINGROUP(80, SOUTH, mdp_vsync, NA, phase_flag17, qdss_gpio0, NA, + NA, NA, NA, NA), + [81] = PINGROUP(81, SOUTH, mdp_vsync, NA, phase_flag13, qdss_gpio, NA, + NA, NA, NA, NA), + [82] = PINGROUP(82, SOUTH, mdp_vsync, NA, phase_flag16, qdss_gpio, NA, + NA, NA, NA, NA), + [83] = PINGROUP(83, SOUTH, NA, phase_flag12, qdss_gpio9, NA, NA, NA, + NA, NA, NA), + [84] = PINGROUP(84, SOUTH, NA, phase_flag18, qdss_gpio10, NA, NA, NA, + NA, NA, NA), + [85] = PINGROUP(85, SOUTH, copy_gp, NA, qdss_gpio11, NA, NA, NA, NA, + NA, NA), + [86] = PINGROUP(86, SOUTH, NA, qdss_gpio14, NA, NA, NA, NA, NA, NA, NA), + [87] = PINGROUP(87, WEST, tsense_pwm, NA, NA, NA, NA, NA, NA, NA, NA), + [88] = PINGROUP(88, WEST, mpm_pwr, tgu_ch3, NA, phase_flag31, NA, NA, + NA, NA, NA), + [89] = PINGROUP(89, WEST, mdp_vsync, mdp_vsync0, mdp_vsync1, + mdp_vsync2, mdp_vsync3, mdp_vsync4, mdp_vsync5, + tgu_ch0, NA), + [90] = PINGROUP(90, WEST, tgu_ch1, atest_char1, NA, NA, NA, NA, NA, NA, + NA), + [91] = PINGROUP(91, WEST, vfr_1, tgu_ch2, NA, phase_flag30, + qdss_gpio10, NA, NA, NA, NA), + [92] = PINGROUP(92, WEST, qdss_gpio11, atest_char0, NA, NA, NA, NA, NA, + NA, NA), + [93] = PINGROUP(93, WEST, NA, phase_flag24, atest_char2, NA, NA, NA, + NA, NA, NA), + [94] = PINGROUP(94, SOUTH, GP_PDM0, NA, qdss_gpio13, atest_char3, NA, + NA, NA, NA, NA), + [95] = PINGROUP(95, SOUTH, qdss_cti, NA, NA, NA, NA, NA, NA, NA, NA), + [96] = PINGROUP(96, SOUTH, mdp_vsync, ldo_en, qdss_gpio15, NA, NA, NA, + NA, NA, NA), + [97] = PINGROUP(97, SOUTH, mdp_vsync, ldo_update, NA, NA, NA, NA, NA, + NA, NA), + [98] = PINGROUP(98, SOUTH, NA, phase_flag19, prng_rosc, NA, NA, NA, NA, + NA, NA), + [99] = PINGROUP(99, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [100] = PINGROUP(100, SOUTH, dp_hot, prng_rosc, qdss_gpio12, NA, NA, + NA, NA, NA, NA), + [101] = PINGROUP(101, SOUTH, debug_hot, COPY_PHASE, qdss_cti, NA, NA, + NA, NA, NA, NA), + [102] = PINGROUP(102, SOUTH, usb_phy, NA, qdss_gpio, atest_char, NA, + NA, NA, NA, NA), + [103] = PINGROUP(103, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [104] = PINGROUP(104, EAST, mss_lte, NA, NA, NA, NA, NA, NA, NA, NA), + [105] = PINGROUP(105, EAST, mss_lte, NA, NA, NA, NA, NA, NA, NA, NA), + [106] = PINGROUP(106, EAST, swr_tx, aud_sb, qua_mi2s, NA, qdss_cti, NA, + NA, NA, NA), + [107] = PINGROUP(107, EAST, swr_tx, aud_sb, qua_mi2s, NA, qdss_cti, NA, + NA, NA, NA), + [108] = PINGROUP(108, EAST, swr_tx, aud_sb, qua_mi2s, NA, NA, NA, NA, + NA, NA), + [109] = PINGROUP(109, EAST, swr_tx, aud_sb, qua_mi2s, NA, NA, NA, NA, + NA, NA), + [110] = PINGROUP(110, EAST, swr_rx, qua_mi2s, NA, qdss_cti, NA, NA, NA, + NA, NA), + [111] = PINGROUP(111, EAST, swr_rx, qua_mi2s, edp_hot, NA, qdss_cti, + NA, NA, NA, NA), + [112] = PINGROUP(112, EAST, swr_rx, audio_ref, NA, NA, NA, NA, NA, NA, + NA), + [113] = PINGROUP(113, EAST, pri_mi2s, NA, NA, NA, NA, NA, NA, NA, NA), + [114] = PINGROUP(114, EAST, pri_mi2s_ws, qdss_gpio, NA, NA, NA, NA, NA, + NA, NA), + [115] = PINGROUP(115, EAST, pri_mi2s, qdss_gpio0, NA, NA, NA, NA, NA, + NA, NA), + [116] = PINGROUP(116, EAST, pri_mi2s, adsp_ext, qdss_gpio1, NA, NA, NA, + NA, NA, NA), + [117] = PINGROUP(117, SOUTH, edp_lcd, qdss_gpio2, NA, NA, NA, NA, NA, + NA, NA), + [118] = PINGROUP(118, SOUTH, mclk2, m_voc, qdss_gpio3, NA, NA, NA, NA, + NA, NA), + [119] = PINGROUP(119, SOUTH, mclk1, NA, NA, NA, NA, NA, NA, NA, NA), + [120] = PINGROUP(120, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [121] = PINGROUP(121, EAST, qca_sb, qui_mi2s, NA, NA, NA, NA, NA, NA, + NA), + [122] = PINGROUP(122, EAST, qca_sb, qui_mi2s, NA, NA, NA, NA, NA, NA, + NA), + [123] = PINGROUP(123, EAST, qui_mi2s, NA, NA, NA, NA, NA, NA, NA, NA), + [124] = PINGROUP(124, EAST, qui_mi2s, NA, NA, NA, NA, NA, NA, NA, NA), + [125] = PINGROUP(125, EAST, DMIC0_CLK, sec_mi2s, NA, NA, NA, NA, NA, + NA, NA), + [126] = PINGROUP(126, EAST, DMIC0_DATA, sec_mi2s, NA, NA, NA, NA, NA, + NA, NA), + [127] = PINGROUP(127, EAST, DMIC1_CLK, sec_mi2s, NA, NA, NA, NA, NA, + NA, NA), + [128] = PINGROUP(128, EAST, DMIC1_DATA, sec_mi2s, NA, NA, NA, NA, NA, + NA, NA), + [129] = PINGROUP(129, SOUTH, NA, phase_flag14, NA, NA, NA, NA, NA, NA, + NA), + [130] = PINGROUP(130, SOUTH, phase_flag21, NA, NA, NA, NA, NA, NA, NA, + NA), + [131] = PINGROUP(131, SOUTH, phase_flag20, NA, NA, NA, NA, NA, NA, NA, + NA), + [132] = PINGROUP(132, SOUTH, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [133] = SDC_QDSD_PINGROUP(sdc1_rclk, 0x18d000, 15, 0), + [134] = SDC_QDSD_PINGROUP(sdc1_clk, 0x18d000, 13, 6), + [135] = SDC_QDSD_PINGROUP(sdc1_cmd, 0x18d000, 11, 3), + [136] = SDC_QDSD_PINGROUP(sdc1_data, 0x18d000, 9, 0), + [137] = SDC_QDSD_PINGROUP(sdc2_clk, 0x58b000, 14, 6), + [138] = SDC_QDSD_PINGROUP(sdc2_cmd, 0x58b000, 11, 3), + [139] = SDC_QDSD_PINGROUP(sdc2_data, 0x58b000, 9, 0), + [140] = UFS_RESET(ufs_reset, 0x190000), +}; + +static const struct msm_pinctrl_soc_data trinket_pinctrl = { + .pins = trinket_pins, + .npins = ARRAY_SIZE(trinket_pins), + .functions = trinket_functions, + .nfunctions = ARRAY_SIZE(trinket_functions), + .groups = trinket_groups, + .ngroups = ARRAY_SIZE(trinket_groups), + .ngpios = 133, +}; + +static int trinket_pinctrl_probe(struct platform_device *pdev) +{ + return msm_pinctrl_probe(pdev, &trinket_pinctrl); +} + +static const struct of_device_id trinket_pinctrl_of_match[] = { + { .compatible = "qcom,trinket-pinctrl", }, + { }, +}; + +static struct platform_driver trinket_pinctrl_driver = { + .driver = { + .name = "trinket-pinctrl", + .owner = THIS_MODULE, + .of_match_table = trinket_pinctrl_of_match, + }, + .probe = trinket_pinctrl_probe, + .remove = msm_pinctrl_remove, +}; + +static int __init trinket_pinctrl_init(void) +{ + return platform_driver_register(&trinket_pinctrl_driver); +} +arch_initcall(trinket_pinctrl_init); + +static void __exit trinket_pinctrl_exit(void) +{ + platform_driver_unregister(&trinket_pinctrl_driver); +} +module_exit(trinket_pinctrl_exit); + +MODULE_DESCRIPTION("QTI trinket pinctrl driver"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, trinket_pinctrl_of_match); diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index 241c4bd3d070d1a8aa9ef8a2b72cf90242f2ab81..95a179df73d07389be8319c43cbe4eee0090b869 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -92,9 +92,6 @@ static void __gsi_config_ieob_irq(int ee, uint32_t mask, uint32_t val) GSI_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_OFFS(ee)); gsi_writel((curr & ~mask) | (val & mask), gsi_ctx->base + GSI_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_OFFS(ee)); - if (gsi_ctx->per.ver == GSI_VER_2_2) - gsi_ctx->chan_ieob_mask = ((gsi_ctx->chan_ieob_mask & ~mask) | - (val & mask)); } static void __gsi_config_glob_irq(int ee, uint32_t mask, uint32_t val) @@ -564,29 +561,10 @@ static void gsi_handle_ieob(int ee) unsigned long cntr; uint32_t msk; - if (gsi_ctx->per.ver == GSI_VER_2_2) { - /* Masking IEOB global interrupt*/ - __gsi_config_type_irq(ee, - 1 << GSI_EE_n_CNTXT_TYPE_IRQ_MSK_IEOB_SHFT, 0); - ch = gsi_readl(gsi_ctx->base + - GSI_EE_n_CNTXT_SRC_IEOB_IRQ_OFFS(ee)); - msk = gsi_readl(gsi_ctx->base + - GSI_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_OFFS(ee)); - if (gsi_ctx->chan_ieob_mask != msk) - gsi_ctx->ieob_mask_miss_match_cnt++; - /* In GSI 2.2 there is a limitation that can lead - * to losing an interrupt because of wrong IEOB IRQ mask value. - * For these versions an explicit considering mask value for - * all the event channel. - */ - msk = 0xffff; - } else { - ch = gsi_readl(gsi_ctx->base + - GSI_EE_n_CNTXT_SRC_IEOB_IRQ_OFFS(ee)); - msk = gsi_readl(gsi_ctx->base + - GSI_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_OFFS(ee)); - } - + ch = gsi_readl(gsi_ctx->base + + GSI_EE_n_CNTXT_SRC_IEOB_IRQ_OFFS(ee)); + msk = gsi_readl(gsi_ctx->base + + GSI_EE_n_CNTXT_SRC_IEOB_IRQ_MSK_OFFS(ee)); gsi_writel(ch & msk, gsi_ctx->base + GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_OFFS(ee)); @@ -633,11 +611,6 @@ static void gsi_handle_ieob(int ee) spin_unlock_irqrestore(&ctx->ring.slock, flags); } } - if (gsi_ctx->per.ver == GSI_VER_2_2) { - /* Unmasking IEOB global interrupt*/ - __gsi_config_type_irq(ee, - 1 << GSI_EE_n_CNTXT_TYPE_IRQ_MSK_IEOB_SHFT, ~0); - } } static void gsi_handle_inter_ee_ch_ctrl(int ee) @@ -1127,7 +1100,6 @@ int gsi_register_device(struct gsi_per_props *props, unsigned long *dev_hdl) props->emulator_intcntrlr_client_isr; } - gsi_ctx->chan_ieob_mask = 0; gsi_ctx->per = *props; gsi_ctx->per_registered = true; mutex_init(&gsi_ctx->mlock); @@ -1230,6 +1202,8 @@ EXPORT_SYMBOL(gsi_register_device); int gsi_write_device_scratch(unsigned long dev_hdl, struct gsi_device_scratch *val) { + unsigned int max_usb_pkt_size = 0; + if (!gsi_ctx) { pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__); return -GSI_STATUS_NODEV; @@ -1248,7 +1222,8 @@ int gsi_write_device_scratch(unsigned long dev_hdl, if (val->max_usb_pkt_size_valid && val->max_usb_pkt_size != 1024 && - val->max_usb_pkt_size != 512) { + val->max_usb_pkt_size != 512 && + val->max_usb_pkt_size != 64) { GSIERR("bad USB max pkt size dev_hdl=0x%lx sz=%u\n", dev_hdl, val->max_usb_pkt_size); return -GSI_STATUS_INVALID_PARAMS; @@ -1258,9 +1233,15 @@ int gsi_write_device_scratch(unsigned long dev_hdl, if (val->mhi_base_chan_idx_valid) gsi_ctx->scratch.word0.s.mhi_base_chan_idx = val->mhi_base_chan_idx; - if (val->max_usb_pkt_size_valid) - gsi_ctx->scratch.word0.s.max_usb_pkt_size = - (val->max_usb_pkt_size == 1024) ? 1 : 0; + + if (val->max_usb_pkt_size_valid) { + max_usb_pkt_size = 2; + if (val->max_usb_pkt_size > 64) + max_usb_pkt_size = + (val->max_usb_pkt_size == 1024) ? 1 : 0; + gsi_ctx->scratch.word0.s.max_usb_pkt_size = max_usb_pkt_size; + } + gsi_writel(gsi_ctx->scratch.word0.val, gsi_ctx->base + GSI_EE_n_CNTXT_SCRATCH_0_OFFS(gsi_ctx->per.ee)); @@ -2231,6 +2212,57 @@ int gsi_alloc_channel(struct gsi_chan_props *props, unsigned long dev_hdl, } EXPORT_SYMBOL(gsi_alloc_channel); +static int gsi_alloc_ap_channel(unsigned int chan_hdl) +{ + struct gsi_chan_ctx *ctx; + uint32_t val; + int res; + int ee; + enum gsi_ch_cmd_opcode op = GSI_CH_ALLOCATE; + + if (!gsi_ctx) { + pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__); + return -GSI_STATUS_NODEV; + } + + ctx = &gsi_ctx->chan[chan_hdl]; + if (ctx->allocated) { + GSIERR("chan %d already allocated\n", chan_hdl); + return -GSI_STATUS_NODEV; + } + + memset(ctx, 0, sizeof(*ctx)); + + mutex_init(&ctx->mlock); + init_completion(&ctx->compl); + atomic_set(&ctx->poll_mode, GSI_CHAN_MODE_CALLBACK); + + mutex_lock(&gsi_ctx->mlock); + ee = gsi_ctx->per.ee; + gsi_ctx->ch_dbg[chan_hdl].ch_allocate++; + val = (((chan_hdl << GSI_EE_n_GSI_CH_CMD_CHID_SHFT) & + GSI_EE_n_GSI_CH_CMD_CHID_BMSK) | + ((op << GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT) & + GSI_EE_n_GSI_CH_CMD_OPCODE_BMSK)); + gsi_writel(val, gsi_ctx->base + + GSI_EE_n_GSI_CH_CMD_OFFS(ee)); + res = wait_for_completion_timeout(&ctx->compl, GSI_CMD_TIMEOUT); + if (res == 0) { + GSIERR("chan_hdl=%u timed out\n", chan_hdl); + mutex_unlock(&gsi_ctx->mlock); + return -GSI_STATUS_TIMED_OUT; + } + if (ctx->state != GSI_CHAN_STATE_ALLOCATED) { + GSIERR("chan_hdl=%u allocation failed state=%d\n", + chan_hdl, ctx->state); + mutex_unlock(&gsi_ctx->mlock); + return -GSI_STATUS_RES_ALLOC_FAILURE; + } + mutex_unlock(&gsi_ctx->mlock); + + return GSI_STATUS_SUCCESS; +} + static void __gsi_write_channel_scratch(unsigned long chan_hdl, union __packed gsi_channel_scratch val) { @@ -2249,6 +2281,36 @@ static void __gsi_write_channel_scratch(unsigned long chan_hdl, gsi_ctx->per.ee)); } +int gsi_write_channel_scratch3_reg(unsigned long chan_hdl, + union __packed gsi_wdi_channel_scratch3_reg val) +{ + struct gsi_chan_ctx *ctx; + + if (!gsi_ctx) { + pr_err("%s:%d gsi context not allocated\n", __func__, __LINE__); + return -GSI_STATUS_NODEV; + } + + if (chan_hdl >= gsi_ctx->max_ch) { + GSIERR("bad params chan_hdl=%lu\n", chan_hdl); + return -GSI_STATUS_INVALID_PARAMS; + } + + ctx = &gsi_ctx->chan[chan_hdl]; + + mutex_lock(&ctx->mlock); + + ctx->scratch.wdi.endp_metadatareg_offset = + val.wdi.endp_metadatareg_offset; + ctx->scratch.wdi.qmap_id = val.wdi.qmap_id; + + gsi_writel(val.data.word1, gsi_ctx->base + + GSI_EE_n_GSI_CH_k_SCRATCH_3_OFFS(chan_hdl, + gsi_ctx->per.ee)); + mutex_unlock(&ctx->mlock); + return GSI_STATUS_SUCCESS; +} + static void __gsi_read_channel_scratch(unsigned long chan_hdl, union __packed gsi_channel_scratch * val) { @@ -3267,6 +3329,33 @@ int gsi_config_channel_mode(unsigned long chan_hdl, enum gsi_chan_mode mode) mode == GSI_CHAN_MODE_CALLBACK) { atomic_set(&ctx->poll_mode, mode); __gsi_config_ieob_irq(gsi_ctx->per.ee, 1 << ctx->evtr->id, ~0); + + /* + * In GSI 2.2 and 2.5 there is a limitation that can lead + * to losing an interrupt. For these versions an + * explicit check is needed after enabling the interrupt + */ + if (gsi_ctx->per.ver == GSI_VER_2_2 || + gsi_ctx->per.ver == GSI_VER_2_5) { + u32 src = gsi_readl(gsi_ctx->base + + GSI_EE_n_CNTXT_SRC_IEOB_IRQ_OFFS( + gsi_ctx->per.ee)); + if (src & (1 << ctx->evtr->id)) { + __gsi_config_ieob_irq( + gsi_ctx->per.ee, 1 << ctx->evtr->id, 0); + gsi_writel(1 << ctx->evtr->id, gsi_ctx->base + + GSI_EE_n_CNTXT_SRC_IEOB_IRQ_CLR_OFFS( + gsi_ctx->per.ee)); + spin_unlock_irqrestore(&gsi_ctx->slock, flags); + spin_lock_irqsave(&ctx->ring.slock, flags); + atomic_set( + &ctx->poll_mode, GSI_CHAN_MODE_POLL); + spin_unlock_irqrestore( + &ctx->ring.slock, flags); + ctx->stats.poll_pending_irq++; + return -GSI_STATUS_PENDING_IRQ; + } + } ctx->stats.poll_to_callback++; } spin_unlock_irqrestore(&gsi_ctx->slock, flags); @@ -3633,6 +3722,9 @@ int gsi_alloc_channel_ee(unsigned int chan_idx, unsigned int ee, int *code) return -GSI_STATUS_INVALID_PARAMS; } + if (ee == 0) + return gsi_alloc_ap_channel(chan_idx); + mutex_lock(&gsi_ctx->mlock); reinit_completion(&gsi_ctx->gen_ee_cmd_compl); diff --git a/drivers/platform/msm/gsi/gsi.h b/drivers/platform/msm/gsi/gsi.h index b5ef9a4b5d0185aa5e5b0dc4faf18b41115d5b01..3a0a7694cfe1c992c650325676f01e4e9caa1a70 100644 --- a/drivers/platform/msm/gsi/gsi.h +++ b/drivers/platform/msm/gsi/gsi.h @@ -120,6 +120,7 @@ struct gsi_chan_stats { unsigned long completed; unsigned long callback_to_poll; unsigned long poll_to_callback; + unsigned long poll_pending_irq; unsigned long invalid_tre_error; unsigned long poll_ok; unsigned long poll_empty; @@ -219,8 +220,6 @@ struct gsi_ctx { u32 intcntrlr_mem_size; irq_handler_t intcntrlr_gsi_isr; irq_handler_t intcntrlr_client_isr; - u32 chan_ieob_mask; - u32 ieob_mask_miss_match_cnt; }; enum gsi_re_type { diff --git a/drivers/platform/msm/gsi/gsi_dbg.c b/drivers/platform/msm/gsi/gsi_dbg.c index dab8dc29e20b75a3cb763a8eae478dd8efa20901..e3b2fe423852b1f6f39e18b1ea8db5b5546e9944 100644 --- a/drivers/platform/msm/gsi/gsi_dbg.c +++ b/drivers/platform/msm/gsi/gsi_dbg.c @@ -273,9 +273,10 @@ static void gsi_dump_ch_stats(struct gsi_chan_ctx *ctx) PRT_STAT("queued=%lu compl=%lu\n", ctx->stats.queued, ctx->stats.completed); - PRT_STAT("cb->poll=%lu poll->cb=%lu\n", + PRT_STAT("cb->poll=%lu poll->cb=%lu poll_pend_irq=%lu\n", ctx->stats.callback_to_poll, - ctx->stats.poll_to_callback); + ctx->stats.poll_to_callback, + ctx->stats.poll_pending_irq); PRT_STAT("invalid_tre_error=%lu\n", ctx->stats.invalid_tre_error); PRT_STAT("poll_ok=%lu poll_empty=%lu\n", diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_gsb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_gsb.c index f139d9efdfa143bf6f86d5addaa0f0df7608b272..354cf05333c65d16a549eea9849b9ee60aed95ac 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_gsb.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_gsb.c @@ -1135,7 +1135,7 @@ int ipa_bridge_set_perf_profile(u32 hdl, u32 bandwidth) mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]); - ret = ipa_pm_set_perf_profile(ipa_gsb_ctx->pm_hdl, + ret = ipa_pm_set_throughput(ipa_gsb_ctx->pm_hdl, bandwidth); if (ret) IPA_GSB_ERR("fail to set perf profile\n"); diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c index ca0ca72b2e81e362c7647dbbc0163b43e9efbadb..bc55db746dd75c5173d5b802a218e3d452c5724c 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c @@ -2596,7 +2596,7 @@ static int ipa_mhi_register_pm(void) goto fail_pm_cons; } - res = ipa_pm_set_perf_profile(ipa_mhi_client_ctx->pm_hdl, 1000); + res = ipa_pm_set_throughput(ipa_mhi_client_ctx->pm_hdl, 1000); if (res) { IPA_MHI_ERR("fail to set perf profile to PM %d\n", res); goto fail_pm_cons; diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c b/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c index c74d3b1ba1362983e6d2cec450d03ef9d9f113a0..525796289b74ccb71e6f249600c8b9c1441d1b0e 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c @@ -595,7 +595,7 @@ int ipa_set_perf_profile(struct ipa_perf_profile *profile) } if (ipa_pm_is_used()) - return ipa_pm_set_perf_profile( + return ipa_pm_set_throughput( ipa_uc_offload_ctx[IPA_UC_NTN]->pm_hdl, profile->max_supported_bw_mbps); diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c index 73369ed2fc639d902647381e51876227d0360d7b..ac3d62e4de0b19f5660ee2e3726576bf93372c51 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c @@ -1493,7 +1493,7 @@ static bool ipa3_usb_check_connect_params( IPA_USB_DBG_LOW("max_supported_bandwidth_mbps = %d\n", params->max_supported_bandwidth_mbps); - if (params->max_pkt_size < IPA_USB_HIGH_SPEED_512B || + if (params->max_pkt_size < IPA_USB_FULL_SPEED_64B || params->max_pkt_size > IPA_USB_SUPER_SPEED_1024B || params->ipa_to_usb_xferrscidx > 127 || (params->teth_prot != IPA_USB_DIAG && @@ -1848,7 +1848,7 @@ static int ipa3_usb_xdci_connect_internal( if (ipa_pm_is_used()) { /* perf profile is not set on USB DPL pipe */ if (ttype != IPA_USB_TRANSPORT_DPL) { - result = ipa_pm_set_perf_profile( + result = ipa_pm_set_throughput( ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl, params->max_supported_bandwidth_mbps); if (result) { diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_wdi3.c b/drivers/platform/msm/ipa/ipa_clients/ipa_wdi3.c index e51c567fe4a72173fd52e9fbb96fe4e35414c7c3..625ce4a0f7418fdc0a2b0c5a7e1f84087f5622f1 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_wdi3.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_wdi3.c @@ -846,7 +846,7 @@ int ipa_wdi_set_perf_profile(struct ipa_wdi_perf_profile *profile) return -EFAULT; } } else { - if (ipa_pm_set_perf_profile(ipa_wdi_ctx->ipa_pm_hdl, + if (ipa_pm_set_throughput(ipa_wdi_ctx->ipa_pm_hdl, profile->max_supported_bw_mbps)) { IPA_WDI_ERR("fail to setup pm perf profile\n"); return -EFAULT; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 0d750b8fd605c5cd7cdfcb6b22e138f0140f9608..888f4ed54807a0d0b4156c513f7bef5656466233 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -6977,6 +6977,44 @@ int ipa3_get_smmu_params(struct ipa_smmu_in_params *in, return 0; } +#define MAX_LEN 96 + +void ipa_pc_qmp_enable(void) +{ + char buf[MAX_LEN] = "{class: bcm, res: ipa_pc, val: 1}"; + struct qmp_pkt pkt; + int ret = 0; + + /* prepare the mailbox struct */ + ipa3_ctx->mbox_client.dev = &ipa3_ctx->master_pdev->dev; + ipa3_ctx->mbox_client.tx_block = true; + ipa3_ctx->mbox_client.tx_tout = MBOX_TOUT_MS; + ipa3_ctx->mbox_client.knows_txdone = false; + + ipa3_ctx->mbox = mbox_request_channel(&ipa3_ctx->mbox_client, 0); + if (IS_ERR(ipa3_ctx->mbox)) { + ret = PTR_ERR(ipa3_ctx->mbox); + if (ret != -EPROBE_DEFER) + IPAERR("mailbox channel request failed, ret=%d\n", ret); + goto cleanup; + } + + /* prepare the QMP packet to send */ + pkt.size = MAX_LEN; + pkt.data = buf; + + /* send the QMP packet to AOP */ + ret = mbox_send_message(ipa3_ctx->mbox, &pkt); + if (ret < 0) { + IPAERR("qmp message send failed, ret=%d\n", ret); + goto cleanup; + } + +cleanup: + ipa3_ctx->mbox = NULL; + mbox_free_channel(ipa3_ctx->mbox); +} + /************************************************************** * PCIe Version *************************************************************/ diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c index b42358d6127ef5a007d3c125748578038dbb4b4a..298c81b884392fda7eba1c64ec404a70afbf8c8a 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c @@ -431,11 +431,16 @@ static int ipa3_attrib_dump(struct ipa_rule_attrib *attrib, uint32_t mask[4]; int i; - if (attrib->attrib_mask & IPA_FLT_TOS_MASKED) - pr_err("tos_value:%d ", attrib->tos_value); + if (attrib->attrib_mask & IPA_FLT_IS_PURE_ACK) + pr_err("is_pure_ack "); - if (attrib->attrib_mask & IPA_FLT_TOS_MASKED) - pr_err("tos_mask:%d ", attrib->tos_mask); + if (attrib->attrib_mask & IPA_FLT_TOS) + pr_cont("tos:%d ", attrib->u.v4.tos); + + if (attrib->attrib_mask & IPA_FLT_TOS_MASKED) { + pr_cont("tos_value:%d ", attrib->tos_value); + pr_cont("tos_mask:%d ", attrib->tos_mask); + } if (attrib->attrib_mask & IPA_FLT_PROTOCOL) pr_err("protocol:%d ", attrib->u.v4.protocol); @@ -557,8 +562,12 @@ static int ipa3_attrib_dump_eq(struct ipa_ipfltri_rule_eq *attrib) int i; int j; - if (attrib->tos_eq_present) - pr_err("tos_value:%d ", attrib->tos_eq); + if (attrib->tos_eq_present) { + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5) + pr_err("pure_ack "); + else + pr_err("tos:%d ", attrib->tos_eq); + } if (attrib->protocol_eq_present) pr_err("protocol:%d ", attrib->protocol_eq); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index ba44fd865f386b282cddca55bd45fd3fbf96ec5e..817cb777efee9776060790ae989c67868226d6dd 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -30,6 +30,8 @@ #define POLLING_INACTIVITY_TX 40 #define POLLING_MIN_SLEEP_TX 400 #define POLLING_MAX_SLEEP_TX 500 +#define SUSPEND_MIN_SLEEP_RX 1000 +#define SUSPEND_MAX_SLEEP_RX 1005 /* 8K less 1 nominal MTU (1500 bytes) rounded to units of KB */ #define IPA_MTU 1500 #define IPA_GENERIC_AGGR_BYTE_LIMIT 6 @@ -752,27 +754,24 @@ static int ipa3_handle_rx_core(struct ipa3_sys_context *sys, bool process_all, /** * ipa3_rx_switch_to_intr_mode() - Operate the Rx data path in interrupt mode */ -static void ipa3_rx_switch_to_intr_mode(struct ipa3_sys_context *sys) +static int ipa3_rx_switch_to_intr_mode(struct ipa3_sys_context *sys) { int ret; - if (!atomic_read(&sys->curr_polling_state)) { - IPAERR("already in intr mode\n"); - goto fail; - } atomic_set(&sys->curr_polling_state, 0); ipa3_dec_release_wakelock(); ret = gsi_config_channel_mode(sys->ep->gsi_chan_hdl, GSI_CHAN_MODE_CALLBACK); if (ret != GSI_STATUS_SUCCESS) { - IPAERR("Failed to switch to intr mode.\n"); - goto fail; + if (ret == -GSI_STATUS_PENDING_IRQ) { + ipa3_inc_acquire_wakelock(); + atomic_set(&sys->curr_polling_state, 1); + } else { + IPAERR("Failed to switch to intr mode.\n"); + } } - return; -fail: - queue_delayed_work(sys->wq, &sys->switch_to_intr_work, - msecs_to_jiffies(1)); + return ret; } /** @@ -785,13 +784,16 @@ static void ipa3_rx_switch_to_intr_mode(struct ipa3_sys_context *sys) */ static void ipa3_handle_rx(struct ipa3_sys_context *sys) { - int inactive_cycles = 0; + int inactive_cycles; int cnt; + int ret; if (ipa3_ctx->use_ipa_pm) ipa_pm_activate_sync(sys->pm_hdl); else IPA_ACTIVE_CLIENTS_INC_SIMPLE(); +start_poll: + inactive_cycles = 0; do { cnt = ipa3_handle_rx_core(sys, true, true); if (cnt == 0) @@ -814,7 +816,10 @@ static void ipa3_handle_rx(struct ipa3_sys_context *sys) } while (inactive_cycles <= POLLING_INACTIVITY_RX); trace_poll_to_intr3(sys->ep->client); - ipa3_rx_switch_to_intr_mode(sys); + ret = ipa3_rx_switch_to_intr_mode(sys); + if (ret == -GSI_STATUS_PENDING_IRQ) + goto start_poll; + if (ipa3_ctx->use_ipa_pm) ipa_pm_deferred_deactivate(sys->pm_hdl); else @@ -829,7 +834,7 @@ static void ipa3_switch_to_intr_rx_work_func(struct work_struct *work) dwork = container_of(work, struct delayed_work, work); sys = container_of(dwork, struct ipa3_sys_context, switch_to_intr_work); - if (sys->ep->napi_enabled) { + if (sys->napi_obj) { /* interrupt mode is done in ipa3_rx_poll context */ ipa_assert(); } else @@ -861,11 +866,24 @@ static void ipa_pm_sys_pipe_cb(void *p, enum ipa_pm_cb_event event) * pipe will be unsuspended as part of * enabling IPA clocks */ - ipa_pm_activate(sys->pm_hdl); - ipa_pm_deferred_deactivate(sys->pm_hdl); + IPADBG("calling wakeup for client %d\n", sys->ep->client); + if (sys->ep->client == IPA_CLIENT_APPS_WAN_CONS) { + IPA_ACTIVE_CLIENTS_INC_SPECIAL("PIPE_SUSPEND_WAN"); + usleep_range(SUSPEND_MIN_SLEEP_RX, + SUSPEND_MAX_SLEEP_RX); + IPA_ACTIVE_CLIENTS_DEC_SPECIAL("PIPE_SUSPEND_WAN"); + } else if (sys->ep->client == IPA_CLIENT_APPS_LAN_CONS) { + IPA_ACTIVE_CLIENTS_INC_SPECIAL("PIPE_SUSPEND_LAN"); + usleep_range(SUSPEND_MIN_SLEEP_RX, + SUSPEND_MAX_SLEEP_RX); + IPA_ACTIVE_CLIENTS_DEC_SPECIAL("PIPE_SUSPEND_LAN"); + } else + IPAERR("Unexpected event %d\n for client %d\n", + event, sys->ep->client); break; default: - IPAERR("Unexpected event %d\n", event); + IPAERR("Unexpected event %d\n for client %d\n", + event, sys->ep->client); WARN_ON(1); return; } @@ -983,7 +1001,7 @@ int ipa3_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl) } } - result = ipa_pm_set_perf_profile(ep->sys->pm_hdl, + result = ipa_pm_set_throughput(ep->sys->pm_hdl, IPA_APPS_BW_FOR_PM); if (result) { IPAERR("failed to set profile IPA PM client\n"); @@ -1004,7 +1022,7 @@ int ipa3_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl) ep->valid = 1; ep->client = sys_in->client; ep->client_notify = sys_in->notify; - ep->napi_enabled = sys_in->napi_enabled; + ep->sys->napi_obj = sys_in->napi_obj; ep->priv = sys_in->priv; ep->keep_ipa_awake = sys_in->keep_ipa_awake; atomic_set(&ep->avail_fifo_desc, @@ -1168,7 +1186,7 @@ int ipa3_teardown_sys_pipe(u32 clnt_hdl) return result; } - if (ep->napi_enabled) { + if (ep->sys->napi_obj) { do { usleep_range(95, 105); } while (atomic_read(&ep->sys->curr_polling_state)); @@ -1523,13 +1541,12 @@ static void ipa3_wq_handle_rx(struct work_struct *work) sys = container_of(work, struct ipa3_sys_context, work); - if (sys->ep->napi_enabled) { + if (sys->napi_obj) { if (!ipa3_ctx->use_ipa_pm) IPA_ACTIVE_CLIENTS_INC_SPECIAL("NAPI"); else ipa_pm_activate_sync(sys->pm_hdl); - sys->ep->client_notify(sys->ep->priv, - IPA_CLIENT_START_POLL, 0); + napi_schedule(sys->napi_obj); } else ipa3_handle_rx(sys); } @@ -2988,7 +3005,7 @@ static int ipa3_assign_policy(struct ipa_sys_connect_params *in, sys->repl_hdlr = ipa3_replenish_rx_cache; } - if (in->napi_enabled && in->recycle_enabled) + if (in->napi_obj && in->recycle_enabled) sys->repl_hdlr = ipa3_replenish_rx_cache_recycle; in->ipa_ep_cfg.aggr.aggr_sw_eof_active @@ -3556,24 +3573,22 @@ void __ipa_gsi_irq_rx_scedule_poll(struct ipa3_sys_context *sys) */ if (ipa3_ctx->use_ipa_pm) { clk_off = ipa_pm_activate(sys->pm_hdl); - if (!clk_off && sys->ep->napi_enabled) { - sys->ep->client_notify(sys->ep->priv, - IPA_CLIENT_START_POLL, 0); + if (!clk_off && sys->napi_obj) { + napi_schedule(sys->napi_obj); return; } queue_work(sys->wq, &sys->work); return; } - if (sys->ep->napi_enabled) { + if (sys->napi_obj) { struct ipa_active_client_logging_info log; IPA_ACTIVE_CLIENTS_PREP_SPECIAL(log, "NAPI"); clk_off = ipa3_inc_client_enable_clks_no_block( &log); if (!clk_off) { - sys->ep->client_notify(sys->ep->priv, - IPA_CLIENT_START_POLL, 0); + napi_schedule(sys->napi_obj); return; } } @@ -3775,7 +3790,7 @@ static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in, ep->gsi_mem_info.evt_ring_base_vaddr = gsi_evt_ring_props.ring_base_vaddr; - if (ep->napi_enabled) { + if (ep->sys->napi_obj) { gsi_evt_ring_props.int_modt = IPA_GSI_EVT_RING_INT_MODT; gsi_evt_ring_props.int_modc = IPA_GSI_EVT_RING_INT_MODC; } else { @@ -4062,6 +4077,7 @@ int ipa3_rx_poll(u32 clnt_hdl, int weight) } ep = &ipa3_ctx->ep[clnt_hdl]; +start_poll: while (remain_aggr_weight > 0 && atomic_read(&ep->sys->curr_polling_state)) { atomic_set(&ipa3_ctx->transport_pm.eot_activity, 1); @@ -4088,8 +4104,12 @@ int ipa3_rx_poll(u32 clnt_hdl, int weight) } cnt += weight - remain_aggr_weight * IPA_WAN_AGGR_PKT_CNT; if (cnt < weight) { - ep->client_notify(ep->priv, IPA_CLIENT_COMP_NAPI, 0); - ipa3_rx_switch_to_intr_mode(ep->sys); + napi_complete(ep->sys->napi_obj); + ret = ipa3_rx_switch_to_intr_mode(ep->sys); + if (ret == -GSI_STATUS_PENDING_IRQ && + napi_reschedule(ep->sys->napi_obj)) + goto start_poll; + if (ipa3_ctx->use_ipa_pm) ipa_pm_deferred_deactivate(ep->sys->pm_hdl); else diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c index f762a3c984f1899d2c984f79797be9f886be626e..93d328587451d0aefd165d9f13a3fc10db0959c4 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c @@ -50,6 +50,26 @@ static int ipa3_generate_flt_hw_rule(enum ipa_ip_type ip, memset(&gen_params, 0, sizeof(gen_params)); + if (entry->rule.hashable) { + if (entry->rule.attrib.attrib_mask & IPA_FLT_IS_PURE_ACK + && !entry->rule.eq_attrib_type) { + IPAERR_RL("PURE_ACK rule atrb used with hash rule\n"); + WARN_ON_RATELIMIT_IPA(1); + return -EPERM; + } + /* + * tos_eq_present field has two meanings: + * tos equation for IPA ver < 4.5 (as the field name reveals) + * pure_ack equation for IPA ver >= 4.5 + */ + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5 && + entry->rule.eq_attrib_type && + entry->rule.eq_attrib.tos_eq_present) { + IPAERR_RL("PURE_ACK rule eq used with hash rule\n"); + return -EPERM; + } + } + gen_params.ipt = ip; if (entry->rt_tbl) gen_params.rt_tbl_idx = entry->rt_tbl->idx; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 269c1b856218116288bbb917b254d3e082bae9fd..28038d2ea965a68813bd9015cb7c3e3fda59edd5 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -36,6 +36,8 @@ #include "../ipa_common_i.h" #include "ipa_uc_offload_i.h" #include "ipa_pm.h" +#include +#include #define IPA_DEV_NAME_MAX_LEN 15 #define DRV_NAME "ipa" @@ -407,6 +409,8 @@ enum { #define IPA_TZ_UNLOCK_ATTRIBUTE 0x0C0311 #define TZ_MEM_PROTECT_REGION_ID 0x10 +#define MBOX_TOUT_MS 100 + struct ipa3_active_client_htable_entry { struct hlist_node list; char id_string[IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN]; @@ -761,7 +765,6 @@ struct ipa3_status_stats { * @disconnect_in_progress: Indicates client disconnect in progress. * @qmi_request_sent: Indicates whether QMI request to enable clear data path * request is sent or not. - * @napi_enabled: when true, IPA call client callback to start polling * @client_lock_unlock: callback function to take mutex lock/unlock for USB * clients */ @@ -793,7 +796,6 @@ struct ipa3_ep_context { u32 gsi_offload_state; bool disconnect_in_progress; u32 qmi_request_sent; - bool napi_enabled; u32 eot_in_poll_err; bool ep_delay_set; @@ -882,6 +884,7 @@ struct ipa3_sys_context { void (*repl_hdlr)(struct ipa3_sys_context *sys); struct ipa3_repl_ctx repl; u32 pkt_sent; + struct napi_struct *napi_obj; /* ordering is important - mutable fields go above */ struct ipa3_ep_context *ep; @@ -1649,6 +1652,8 @@ struct ipa3_context { bool vlan_mode_iface[IPA_VLAN_IF_MAX]; bool wdi_over_pcie; struct ipa3_wdi2_ctx wdi2_ctx; + struct mbox_client mbox_client; + struct mbox_chan *mbox; }; struct ipa3_plat_drv_res { @@ -2650,4 +2655,5 @@ int ipa3_get_transport_info( phys_addr_t *phys_addr_ptr, unsigned long *size_ptr); irq_handler_t ipa3_get_isr(void); +void ipa_pc_qmp_enable(void); #endif /* _IPA3_I_H_ */ diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.c index 4a14a350e2e0168e7d9eb31a9e5825b4bce12d7e..97fc6af4e6fc9ff9d7804d852b1e84b4cd8d805a 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi_proxy.c @@ -183,6 +183,7 @@ struct imp_context { struct imp_dev_info dev_info; struct imp_mhi_driver md; struct mutex mutex; + struct mutex lpm_mutex; enum imp_state state; bool in_lpm; bool lpm_disabled; @@ -477,12 +478,15 @@ struct ipa_mhi_alloc_channel_resp_msg_v01 *imp_handle_allocate_channel_req( IMP_FUNC_ENTRY(); + mutex_lock(&imp_ctx->mutex); + memset(resp, 0, sizeof(*resp)); if (imp_ctx->state != IMP_READY) { IMP_ERR("invalid state %d\n", imp_ctx->state); resp->resp.result = IPA_QMI_RESULT_FAILURE_V01; resp->resp.error = IPA_QMI_ERR_INCOMPATIBLE_STATE_V01; + mutex_unlock(&imp_ctx->mutex); return resp; } @@ -493,6 +497,7 @@ struct ipa_mhi_alloc_channel_resp_msg_v01 *imp_handle_allocate_channel_req( IMP_ERR("invalid tr_info_arr_len %d\n", req->tr_info_arr_len); resp->resp.result = IPA_QMI_RESULT_FAILURE_V01; resp->resp.error = IPA_QMI_ERR_NO_MEMORY_V01; + mutex_unlock(&imp_ctx->mutex); return resp; } @@ -502,11 +507,10 @@ struct ipa_mhi_alloc_channel_resp_msg_v01 *imp_handle_allocate_channel_req( IMP_ERR("no mapping provided, but smmu is enabled\n"); resp->resp.result = IPA_QMI_RESULT_FAILURE_V01; resp->resp.error = IPA_QMI_ERR_INTERNAL_V01; + mutex_unlock(&imp_ctx->mutex); return resp; } - mutex_lock(&imp_ctx->mutex); - if (imp_ctx->dev_info.smmu_enabled) { /* map CTRL */ __map_smmu_info(imp_ctx->md.mhi_dev->dev.parent, @@ -706,6 +710,13 @@ static void imp_mhi_shutdown(void) iommu_unmap(cb->mapping->domain, iova_p, size_p); } } + if (!imp_ctx->in_lpm && + (imp_ctx->state == IMP_READY || + imp_ctx->state == IMP_STARTED)) { + IMP_DBG("devote IMP with state= %d\n", imp_ctx->state); + IPA_ACTIVE_CLIENTS_DEC_SPECIAL("IMP"); + } + imp_ctx->in_lpm = false; imp_ctx->state = IMP_PROBED; IMP_FUNC_EXIT(); @@ -840,10 +851,10 @@ static void imp_mhi_status_cb(struct mhi_device *mhi_dev, enum MHI_CB mhi_cb) { IMP_DBG("%d\n", mhi_cb); - mutex_lock(&imp_ctx->mutex); + mutex_lock(&imp_ctx->lpm_mutex); if (mhi_dev != imp_ctx->md.mhi_dev) { IMP_DBG("ignoring secondary callbacks\n"); - mutex_unlock(&imp_ctx->mutex); + mutex_unlock(&imp_ctx->lpm_mutex); return; } @@ -876,7 +887,7 @@ static void imp_mhi_status_cb(struct mhi_device *mhi_dev, enum MHI_CB mhi_cb) IMP_ERR("unexpected event %d\n", mhi_cb); break; } - mutex_unlock(&imp_ctx->mutex); + mutex_unlock(&imp_ctx->lpm_mutex); } static int imp_probe(struct platform_device *pdev) @@ -940,12 +951,14 @@ static int imp_remove(struct platform_device *pdev) IMP_DBG("devote IMP with state= %d\n", imp_ctx->state); IPA_ACTIVE_CLIENTS_DEC_SPECIAL("IMP"); } - imp_ctx->in_lpm = false; imp_ctx->lpm_disabled = false; - imp_ctx->state = IMP_INVALID; mutex_unlock(&imp_ctx->mutex); + mutex_lock(&imp_ctx->lpm_mutex); + imp_ctx->in_lpm = false; + mutex_unlock(&imp_ctx->lpm_mutex); + return 0; } @@ -983,6 +996,7 @@ void imp_handle_modem_ready(void) return; mutex_init(&imp_ctx->mutex); + mutex_init(&imp_ctx->lpm_mutex); } if (imp_ctx->state != IMP_INVALID) { @@ -1005,6 +1019,9 @@ void imp_handle_modem_shutdown(void) { IMP_FUNC_ENTRY(); + if (!imp_ctx) + return; + mutex_lock(&imp_ctx->mutex); if (imp_ctx->state == IMP_INVALID) { diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_odl.c b/drivers/platform/msm/ipa/ipa_v3/ipa_odl.c index 4129639b64ef032fbf83571fdb7cecdb0b98f3e0..7d3a008ef7c95133f1cde17f51be88f69cfe54f1 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_odl.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_odl.c @@ -315,7 +315,7 @@ int ipa_setup_odl_pipe(void) ipa_odl_ep_cfg->client = IPA_CLIENT_ODL_DPL_CONS; ipa_odl_ep_cfg->notify = odl_ipa_packet_receive_notify; - ipa_odl_ep_cfg->napi_enabled = false; + ipa_odl_ep_cfg->napi_obj = NULL; ipa_odl_ep_cfg->desc_fifo_sz = IPA_ODL_RX_RING_SIZE * IPA_FIFO_ELEMENT_SIZE; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c index 8b40feb6ec911a833bfca568769058678756b4b4..96c00616f94be01ae94cfac9e9643ab959105aa6 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c @@ -14,22 +14,6 @@ #include "ipa_pm.h" #include "ipa_i.h" -static const char *client_state_to_str[IPA_PM_STATE_MAX] = { - __stringify(IPA_PM_DEACTIVATED), - __stringify(IPA_PM_DEACTIVATE_IN_PROGRESS), - __stringify(IPA_PM_ACTIVATE_IN_PROGRESS), - __stringify(IPA_PM_ACTIVATED), - __stringify(IPA_PM_ACTIVATED_PENDING_DEACTIVATION), - __stringify(IPA_PM_ACTIVATED_TIMER_SET), - __stringify(IPA_PM_ACTIVATED_PENDING_RESCHEDULE), -}; - -static const char *ipa_pm_group_to_str[IPA_PM_GROUP_MAX] = { - __stringify(IPA_PM_GROUP_DEFAULT), - __stringify(IPA_PM_GROUP_APPS), - __stringify(IPA_PM_GROUP_MODEM), -}; - #define IPA_PM_DRV_NAME "ipa_pm" @@ -130,6 +114,7 @@ enum ipa_pm_state { IPA_PM_ACTIVATED_PENDING_DEACTIVATION, IPA_PM_ACTIVATED_TIMER_SET, IPA_PM_ACTIVATED_PENDING_RESCHEDULE, + IPA_PM_STATE_MAX }; #define IPA_PM_STATE_ACTIVE(state) \ @@ -196,6 +181,22 @@ struct ipa_pm_ctx { static struct ipa_pm_ctx *ipa_pm_ctx; +static const char *client_state_to_str[IPA_PM_STATE_MAX] = { + __stringify(IPA_PM_DEACTIVATED), + __stringify(IPA_PM_DEACTIVATE_IN_PROGRESS), + __stringify(IPA_PM_ACTIVATE_IN_PROGRESS), + __stringify(IPA_PM_ACTIVATED), + __stringify(IPA_PM_ACTIVATED_PENDING_DEACTIVATION), + __stringify(IPA_PM_ACTIVATED_TIMER_SET), + __stringify(IPA_PM_ACTIVATED_PENDING_RESCHEDULE), +}; + +static const char *ipa_pm_group_to_str[IPA_PM_GROUP_MAX] = { + __stringify(IPA_PM_GROUP_DEFAULT), + __stringify(IPA_PM_GROUP_APPS), + __stringify(IPA_PM_GROUP_MODEM), +}; + /** * pop_max_from_array() -pop the max and move the last element to where the * max was popped @@ -705,11 +706,6 @@ int ipa_pm_register(struct ipa_pm_register_params *params, u32 *hdl) return -EINVAL; } - if (ipa_pm_ctx == NULL) { - IPA_PM_ERR("PM_ctx is null\n"); - return -EINVAL; - } - if (params == NULL || hdl == NULL || params->name == NULL) { IPA_PM_ERR("Invalid Params\n"); return -EINVAL; @@ -853,9 +849,13 @@ int ipa_pm_associate_ipa_cons_to_client(u32 hdl, enum ipa_client_type consumer) } mutex_lock(&ipa_pm_ctx->client_mutex); - idx = ipa_get_ep_mapping(consumer); + if (ipa_pm_ctx->clients[hdl] == NULL) { + mutex_unlock(&ipa_pm_ctx->client_mutex); + IPA_PM_ERR("Client is NULL\n"); + return -EPERM; + } - IPA_PM_DBG("Mapping pipe %d to client %d\n", idx, hdl); + idx = ipa_get_ep_mapping(consumer); if (idx < 0) { mutex_unlock(&ipa_pm_ctx->client_mutex); @@ -863,11 +863,7 @@ int ipa_pm_associate_ipa_cons_to_client(u32 hdl, enum ipa_client_type consumer) return 0; } - if (ipa_pm_ctx->clients[hdl] == NULL) { - mutex_unlock(&ipa_pm_ctx->client_mutex); - IPA_PM_ERR("Client is NULL\n"); - return -EPERM; - } + IPA_PM_DBG("Mapping pipe %d to client %d\n", idx, hdl); if (ipa_pm_ctx->clients_by_pipe[idx] != NULL) { mutex_unlock(&ipa_pm_ctx->client_mutex); @@ -1051,6 +1047,11 @@ int ipa_pm_deferred_deactivate(u32 hdl) case IPA_PM_DEACTIVATE_IN_PROGRESS: case IPA_PM_ACTIVATED_PENDING_RESCHEDULE: break; + case IPA_PM_STATE_MAX: + default: + IPA_PM_ERR("Bad State"); + spin_unlock_irqrestore(&client->state_lock, flags); + return -EINVAL; } IPA_PM_DBG_STATE(hdl, client->name, client->state); spin_unlock_irqrestore(&client->state_lock, flags); @@ -1220,14 +1221,14 @@ int ipa_pm_handle_suspend(u32 pipe_bitmask) } /** - * ipa_pm_set_perf_profile(): Adds/changes the throughput requirement to IPA PM + * ipa_pm_set_throughput(): Adds/changes the throughput requirement to IPA PM * to be used for clock scaling * @hdl: index of the client in the array * @throughput: the new throughput value to be set for that client * * Returns: 0 on success, negative on failure */ -int ipa_pm_set_perf_profile(u32 hdl, int throughput) +int ipa_pm_set_throughput(u32 hdl, int throughput) { struct ipa_pm_client *client; unsigned long flags; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h index 47a03f93824363fe72cf8a49331246d9de53c29a..69e79647f649c1c50b6311f3af6d7c370f081d26 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h @@ -20,8 +20,7 @@ #define IPA_PM_MAX_EX_CL 64 #define IPA_PM_THRESHOLD_MAX 5 #define IPA_PM_EXCEPTION_MAX 2 -#define IPA_PM_DEFERRED_TIMEOUT 100 -#define IPA_PM_STATE_MAX 7 +#define IPA_PM_DEFERRED_TIMEOUT 10 /* * ipa_pm group names @@ -98,7 +97,7 @@ int ipa_pm_activate(u32 hdl); int ipa_pm_activate_sync(u32 hdl); int ipa_pm_deferred_deactivate(u32 hdl); int ipa_pm_deactivate_sync(u32 hdl); -int ipa_pm_set_perf_profile(u32 hdl, int throughput); +int ipa_pm_set_throughput(u32 hdl, int throughput); int ipa_pm_deregister(u32 hdl); /* IPA Internal Functions */ @@ -143,7 +142,7 @@ static inline int ipa_pm_deactivate_sync(u32 hdl) return -EPERM; } -static inline int ipa_pm_set_perf_profile(u32 hdl, int throughput) +static inline int ipa_pm_set_throughput(u32 hdl, int throughput) { return -EPERM; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c index c8dafd05e5d6e1834ad513549117762eb4754ebb..9b727f7416e756a157aaec43d18b105a26f6ca75 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c @@ -399,7 +399,7 @@ static int ipa3_qmi_send_req_wait(struct qmi_handle *client_handle, qmi_txn_cancel(&txn); return ret; } - ret = qmi_txn_wait(&txn, timeout_ms); + ret = qmi_txn_wait(&txn, msecs_to_jiffies(timeout_ms)); return ret; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c index 6191811c4ff9b90d94369502bbd89e972440af96..dccf660a1e4f27894d65653d5aa6a3e857065303 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c @@ -58,6 +58,13 @@ static int ipa_generate_rt_hw_rule(enum ipa_ip_type ip, memset(&gen_params, 0, sizeof(gen_params)); + if (entry->rule.hashable && + entry->rule.attrib.attrib_mask & IPA_FLT_IS_PURE_ACK) { + IPAERR_RL("PURE_ACK rule atrb used with hash rule\n"); + WARN_ON_RATELIMIT_IPA(1); + return -EPERM; + } + gen_params.ipt = ip; gen_params.dst_pipe_idx = ipa3_get_ep_mapping(entry->rule.dst); if (gen_params.dst_pipe_idx == -1) { diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c index 5178354cf1e9f1bce03ee321bba4de4ee6b75cb2..fe4fc5cad0e3f48f9f31f506b82a123ef3d5e294 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c @@ -1857,12 +1857,8 @@ int ipa3_disconnect_gsi_wdi_pipe(u32 clnt_hdl) if (!ep->keep_ipa_awake) IPA_ACTIVE_CLIENTS_INC_EP(ipa3_get_client_mapping(clnt_hdl)); - result = gsi_reset_evt_ring(ep->gsi_evt_ring_hdl); - if (result != GSI_STATUS_SUCCESS) { - IPAERR("Failed to reset evt ring: %d.\n", - result); - goto fail_dealloc_channel; - } + ipa3_reset_gsi_channel(clnt_hdl); + ipa3_reset_gsi_event_ring(clnt_hdl); if (!ep->keep_ipa_awake) IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl)); @@ -2223,6 +2219,8 @@ int ipa3_resume_gsi_wdi_pipe(u32 clnt_hdl) int result = 0; struct ipa3_ep_context *ep; struct ipa_ep_cfg_ctrl ep_cfg_ctrl; + struct gsi_chan_info chan_info; + union __packed gsi_channel_scratch gsi_scratch; IPADBG("ep=%d\n", clnt_hdl); ep = &ipa3_ctx->ep[clnt_hdl]; @@ -2246,6 +2244,19 @@ int ipa3_resume_gsi_wdi_pipe(u32 clnt_hdl) IPAERR("gsi_start_channel failed %d\n", result); ipa_assert(); } + gsi_query_channel_info(ep->gsi_chan_hdl, &chan_info); + gsi_read_channel_scratch(ep->gsi_chan_hdl, &gsi_scratch); + IPADBG("ch=%lu channel base = 0x%llx , event base 0x%llx\n", + ep->gsi_chan_hdl, + ep->gsi_mem_info.chan_ring_base_addr, + ep->gsi_mem_info.evt_ring_base_addr); + IPADBG("RP=0x%llx WP=0x%llx ev_valid=%d ERP=0x%llx EWP=0x%llx\n", + chan_info.rp, chan_info.wp, chan_info.evt_valid, + chan_info.evt_rp, chan_info.evt_wp); + IPADBG("Scratch 0 = %x Scratch 1 = %x Scratch 2 = %x Scratch 3 = %x\n", + gsi_scratch.data.word1, gsi_scratch.data.word2, + gsi_scratch.data.word3, gsi_scratch.data.word4); + ep->gsi_offload_state |= IPA_WDI_RESUMED; IPADBG("exit\n"); return result; @@ -2324,6 +2335,8 @@ int ipa3_suspend_gsi_wdi_pipe(u32 clnt_hdl) bool disable_force_clear = false; struct ipahal_ep_cfg_ctrl_scnd ep_ctrl_scnd = { 0 }; int retry_cnt = 0; + struct gsi_chan_info chan_info; + union __packed gsi_channel_scratch gsi_scratch; ipa_ep_idx = ipa3_get_ep_mapping(ipa3_get_client_mapping(clnt_hdl)); if (ipa_ep_idx < 0) { @@ -2373,14 +2386,22 @@ int ipa3_suspend_gsi_wdi_pipe(u32 clnt_hdl) } else { IPADBG("GSI channel %ld STOP\n", ep->gsi_chan_hdl); } - - res = ipa3_reset_gsi_channel(clnt_hdl); - if (res != GSI_STATUS_SUCCESS) { - IPAERR("Failed to reset chan: %d.\n", res); - goto fail_stop_channel; - } - + gsi_query_channel_info(ep->gsi_chan_hdl, &chan_info); + gsi_read_channel_scratch(ep->gsi_chan_hdl, &gsi_scratch); + IPADBG("ch=%lu channel base = 0x%llx , event base 0x%llx\n", + ep->gsi_chan_hdl, + ep->gsi_mem_info.chan_ring_base_addr, + ep->gsi_mem_info.evt_ring_base_addr); + IPADBG("RP=0x%llx WP=0x%llx ev_valid=%d ERP=0x%llx", + chan_info.rp, chan_info.wp, + chan_info.evt_valid, chan_info.evt_rp); + IPADBG("EWP=0x%llx\n", chan_info.evt_wp); + IPADBG("Scratch 0 = %x Scratch 1 = %x Scratch 2 = %x", + gsi_scratch.data.word1, gsi_scratch.data.word2, + gsi_scratch.data.word3); + IPADBG("Scratch 3 = %x\n", gsi_scratch.data.word4); } + if (disable_force_clear) ipa3_disable_force_clear(clnt_hdl); IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl)); @@ -2539,87 +2560,27 @@ int ipa3_write_qmapid_gsi_wdi_pipe(u32 clnt_hdl, u8 qmap_id) { int result = 0; struct ipa3_ep_context *ep; - union __packed gsi_channel_scratch gsi_scratch; - int retry_cnt = 0; - u32 source_pipe_bitmask = 0; - bool disable_force_clear = false; - struct ipahal_ep_cfg_ctrl_scnd ep_ctrl_scnd = { 0 }; + union __packed gsi_wdi_channel_scratch3_reg gsi_scratch; memset(&gsi_scratch, 0, sizeof(gsi_scratch)); ep = &ipa3_ctx->ep[clnt_hdl]; IPA_ACTIVE_CLIENTS_INC_EP(ipa3_get_client_mapping(clnt_hdl)); - result = gsi_read_channel_scratch(ep->gsi_chan_hdl, &gsi_scratch); - if (result != GSI_STATUS_SUCCESS) { - IPAERR("gsi_read_write_channel_scratch failed %d\n", - result); - goto fail_read_channel_scratch; - } - if (ep->gsi_offload_state == (IPA_WDI_CONNECTED | IPA_WDI_ENABLED | - IPA_WDI_RESUMED)) { - source_pipe_bitmask = 1 << - ipa3_get_ep_mapping(ep->client); - result = ipa3_enable_force_clear(clnt_hdl, - false, source_pipe_bitmask); - if (result) { - /* - * assuming here modem SSR, AP can remove - * the delay in this case - */ - IPAERR("failed to force clear %d\n", result); - IPAERR("remove delay from SCND reg\n"); - ep_ctrl_scnd.endp_delay = false; - ipahal_write_reg_n_fields( - IPA_ENDP_INIT_CTRL_SCND_n, clnt_hdl, - &ep_ctrl_scnd); - } else { - disable_force_clear = true; - } - -retry_gsi_stop: - result = ipa3_stop_gsi_channel(clnt_hdl); - if (result != 0 && result != -GSI_STATUS_AGAIN && - result != -GSI_STATUS_TIMED_OUT) { - IPAERR("GSI stop channel failed %d\n", - result); - goto fail_stop_channel; - } else if (result == -GSI_STATUS_AGAIN) { - IPADBG("GSI stop channel failed retry cnt = %d\n", - retry_cnt); - retry_cnt++; - if (retry_cnt >= GSI_STOP_MAX_RETRY_CNT) - goto fail_stop_channel; - goto retry_gsi_stop; - } else { - IPADBG("GSI channel %ld STOP\n", ep->gsi_chan_hdl); - } - } gsi_scratch.wdi.qmap_id = qmap_id; - result = gsi_write_channel_scratch(ep->gsi_chan_hdl, - gsi_scratch); + gsi_scratch.wdi.endp_metadatareg_offset = ipahal_get_reg_mn_ofst( + IPA_ENDP_INIT_HDR_METADATA_n, 0, clnt_hdl)/4; + + result = gsi_write_channel_scratch3_reg(ep->gsi_chan_hdl, gsi_scratch); if (result != GSI_STATUS_SUCCESS) { IPAERR("gsi_write_channel_scratch failed %d\n", result); goto fail_write_channel_scratch; } - if (ep->gsi_offload_state == (IPA_WDI_CONNECTED | IPA_WDI_ENABLED | - IPA_WDI_RESUMED)) { - result = gsi_start_channel(ep->gsi_chan_hdl); - if (result != GSI_STATUS_SUCCESS) { - IPAERR("gsi_start_channel failed %d\n", result); - goto fail_start_channel; - } - } - - if (disable_force_clear) - ipa3_disable_force_clear(clnt_hdl); + IPADBG("client (ep: %d) qmap_id %d updated\n", clnt_hdl, qmap_id); IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl)); return 0; -fail_start_channel: -fail_read_channel_scratch: fail_write_channel_scratch: -fail_stop_channel: ipa_assert(); return result; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 1756f01da950dec772fa2a3404d57ece209cbe57..3b303b2b69ad1802a355ec2ea123767bc0ccc139 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -174,7 +174,8 @@ #define IPA_v4_2_DST_GROUP_MAX (1) #define IPA_v4_5_MHI_GROUP_PCIE (0) -#define IPA_v4_5_GROUP_UL_DL (1) +#define IPA_v4_5_GROUP_UL_DL_DST (0) +#define IPA_v4_5_GROUP_UL_DL_SRC (1) #define IPA_v4_5_MHI_GROUP_DDR (1) #define IPA_v4_5_MHI_GROUP_DMA (2) #define IPA_v4_5_MHI_GROUP_QDSS (3) @@ -261,7 +262,7 @@ enum ipa_ver { static const struct rsrc_min_max ipa3_rsrc_src_grp_config [IPA_VER_MAX][IPA_RSRC_GRP_TYPE_SRC_MAX][IPA_GROUP_MAX] = { [IPA_3_0] = { - /*UL DL DIAG DMA Not Used uC Rx*/ + /* UL DL DIAG DMA Not Used uC Rx */ [IPA_v3_0_RSRC_GRP_TYPE_SRC_PKT_CONTEXTS] = { {3, 255}, {3, 255}, {1, 255}, {1, 255}, {1, 255}, {2, 255} }, [IPA_v3_0_RSRC_GRP_TYPE_SRC_HDR_SECTORS] = { @@ -280,7 +281,7 @@ static const struct rsrc_min_max ipa3_rsrc_src_grp_config {14, 14}, {16, 16}, {5, 5}, {5, 5}, {0, 0}, {8, 8} }, }, [IPA_3_5] = { - /* LWA_DL UL_DL not used UC_RX_Q, other are invalid */ + /* LWA_DL UL_DL unused UC_RX_Q, other are invalid */ [IPA_v3_5_RSRC_GRP_TYPE_SRC_PKT_CONTEXTS] = { {0, 0}, {1, 255}, {0, 0}, {1, 255}, {0, 0}, {0, 0} }, [IPA_v3_5_RSRC_GRP_TYPE_SRS_DESCRIPTOR_LISTS] = { @@ -293,7 +294,7 @@ static const struct rsrc_min_max ipa3_rsrc_src_grp_config {0, 0}, {20, 20}, {0, 0}, {14, 14}, {0, 0}, {0, 0} }, }, [IPA_3_5_MHI] = { - /* PCIE DDR DMA not used, other are invalid */ + /* PCIE DDR DMA unused, other are invalid */ [IPA_v3_5_RSRC_GRP_TYPE_SRC_PKT_CONTEXTS] = { {4, 4}, {5, 5}, {1, 1}, {0, 0}, {0, 0}, {0, 0} }, [IPA_v3_5_RSRC_GRP_TYPE_SRS_DESCRIPTOR_LISTS] = { @@ -306,7 +307,7 @@ static const struct rsrc_min_max ipa3_rsrc_src_grp_config {14, 14}, {14, 14}, {14, 14}, {0, 0}, {0, 0}, {0, 0} }, }, [IPA_3_5_1] = { - /* LWA_DL UL_DL not used UC_RX_Q, other are invalid */ + /* LWA_DL UL_DL unused UC_RX_Q, other are invalid */ [IPA_v3_5_RSRC_GRP_TYPE_SRC_PKT_CONTEXTS] = { {1, 255}, {1, 255}, {0, 0}, {1, 255}, {0, 0}, {0, 0} }, [IPA_v3_5_RSRC_GRP_TYPE_SRS_DESCRIPTOR_LISTS] = { @@ -319,7 +320,7 @@ static const struct rsrc_min_max ipa3_rsrc_src_grp_config {14, 14}, {20, 20}, {0, 0}, {14, 14}, {0, 0}, {0, 0} }, }, [IPA_4_0] = { - /* LWA_DL UL_DL not used UC_RX_Q, other are invalid */ + /* LWA_DL UL_DL unused UC_RX_Q, other are invalid */ [IPA_v4_0_RSRC_GRP_TYPE_SRC_PKT_CONTEXTS] = { {1, 255}, {1, 255}, {0, 0}, {1, 255}, {0, 0}, {0, 0} }, [IPA_v4_0_RSRC_GRP_TYPE_SRS_DESCRIPTOR_LISTS] = { @@ -332,7 +333,7 @@ static const struct rsrc_min_max ipa3_rsrc_src_grp_config {14, 14}, {20, 20}, {0, 0}, {14, 14}, {0, 0}, {0, 0} }, }, [IPA_4_0_MHI] = { - /* PCIE DDR DMA not used, other are invalid */ + /* PCIE DDR DMA unused, other are invalid */ [IPA_v4_0_RSRC_GRP_TYPE_SRC_PKT_CONTEXTS] = { {4, 4}, {5, 5}, {1, 1}, {0, 0}, {0, 0}, {0, 0} }, [IPA_v4_0_RSRC_GRP_TYPE_SRS_DESCRIPTOR_LISTS] = { @@ -345,7 +346,7 @@ static const struct rsrc_min_max ipa3_rsrc_src_grp_config {14, 14}, {14, 14}, {14, 14}, {0, 0}, {0, 0}, {0, 0} }, }, [IPA_4_1] = { - /* LWA_DL UL_DL not used UC_RX_Q, other are invalid */ + /* LWA_DL UL_DL unused UC_RX_Q, other are invalid */ [IPA_v4_0_RSRC_GRP_TYPE_SRC_PKT_CONTEXTS] = { {1, 63}, {1, 63}, {0, 0}, {1, 63}, {0, 0}, {0, 0} }, [IPA_v4_0_RSRC_GRP_TYPE_SRS_DESCRIPTOR_LISTS] = { @@ -371,9 +372,7 @@ static const struct rsrc_min_max ipa3_rsrc_src_grp_config {5, 5}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} }, }, [IPA_4_5] = { - /* not used UL_DL not used not used UC_RX_Q - * other are invalid - */ + /* unused UL_DL_SRC unused unused UC_RX_Q N/A */ [IPA_v4_0_RSRC_GRP_TYPE_SRC_PKT_CONTEXTS] = { {0, 0}, {1, 63}, {0, 0}, {0, 0}, {1, 63}, {0, 0} }, [IPA_v4_0_RSRC_GRP_TYPE_SRS_DESCRIPTOR_LISTS] = { @@ -386,7 +385,7 @@ static const struct rsrc_min_max ipa3_rsrc_src_grp_config {0, 0}, {24, 24}, {0, 0}, {0, 0}, {8, 8}, {0, 0} }, }, [IPA_4_5_MHI] = { - /* PCIE DDR DMA QDSS not used other are invalid */ + /* PCIE DDR DMA QDSS unused N/A N/A */ [IPA_v4_0_RSRC_GRP_TYPE_SRC_PKT_CONTEXTS] = { {3, 8}, {4, 11}, {1, 1}, {1, 1}, {0, 0}, {0, 0} }, [IPA_v4_0_RSRC_GRP_TYPE_SRS_DESCRIPTOR_LISTS] = { @@ -433,42 +432,42 @@ static const struct rsrc_min_max ipa3_rsrc_dst_grp_config {2, 255}, {1, 255}, {1, 2}, {0, 0}, {0, 0}, {0, 0} }, }, [IPA_4_0] = { - /*LWA_DL UL/DL/DPL uC, other are invalid */ + /* LWA_DL UL/DL/DPL uC, other are invalid */ [IPA_v4_0_RSRC_GRP_TYPE_DST_DATA_SECTORS] = { {4, 4}, {4, 4}, {3, 3}, {2, 2}, {0, 0}, {0, 0} }, [IPA_v4_0_RSRC_GRP_TYPE_DST_DPS_DMARS] = { {2, 255}, {1, 255}, {1, 2}, {0, 2}, {0, 0}, {0, 0} }, }, [IPA_4_0_MHI] = { - /*LWA_DL UL/DL/DPL uC, other are invalid */ + /* LWA_DL UL/DL/DPL uC, other are invalid */ [IPA_v4_0_RSRC_GRP_TYPE_DST_DATA_SECTORS] = { {4, 4}, {4, 4}, {3, 3}, {2, 2}, {0, 0}, {0, 0} }, [IPA_v4_0_RSRC_GRP_TYPE_DST_DPS_DMARS] = { {2, 255}, {1, 255}, {1, 2}, {0, 2}, {0, 0}, {0, 0} }, }, [IPA_4_1] = { - /*LWA_DL UL/DL/DPL uC, other are invalid */ + /* LWA_DL UL/DL/DPL uC, other are invalid */ [IPA_v4_0_RSRC_GRP_TYPE_DST_DATA_SECTORS] = { {4, 4}, {4, 4}, {3, 3}, {2, 2}, {0, 0}, {0, 0} }, [IPA_v4_0_RSRC_GRP_TYPE_DST_DPS_DMARS] = { {2, 63}, {1, 63}, {1, 2}, {0, 2}, {0, 0}, {0, 0} }, }, [IPA_4_2] = { - /*UL/DL/DPL, other are invalid */ + /* UL/DL/DPL, other are invalid */ [IPA_v4_0_RSRC_GRP_TYPE_DST_DATA_SECTORS] = { {3, 3}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} }, [IPA_v4_0_RSRC_GRP_TYPE_DST_DPS_DMARS] = { {1, 63}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} }, }, [IPA_4_5] = { - /* not-used UL/DL/DPL not-used not-used uC other are invalid */ + /* UL/DL/DPL_DST unused unused unused uC N/A */ [IPA_v4_0_RSRC_GRP_TYPE_DST_DATA_SECTORS] = { - {0, 0}, {5, 5}, {0, 0}, {0, 0}, {0, 0}, {0, 0} }, + {16, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} }, [IPA_v4_0_RSRC_GRP_TYPE_DST_DPS_DMARS] = { - {0, 0}, {1, 63}, {0, 0}, {0, 0}, {0, 2}, {0, 0} }, + {2, 63}, {0, 0}, {0, 0}, {0, 0}, {0, 2}, {0, 0} }, }, [IPA_4_5_MHI] = { - /* PCIE/DPL DDR DMA/CV2X QDSS uC other are invalid */ + /* PCIE/DPL DDR DMA/CV2X QDSS uC N/A */ [IPA_v4_0_RSRC_GRP_TYPE_DST_DATA_SECTORS] = { {16, 16}, {5, 5}, {2, 2}, {2, 2}, {0, 0}, {0, 0} }, [IPA_v4_0_RSRC_GRP_TYPE_DST_DPS_DMARS] = { @@ -479,7 +478,7 @@ static const struct rsrc_min_max ipa3_rsrc_dst_grp_config static const struct rsrc_min_max ipa3_rsrc_rx_grp_config [IPA_VER_MAX][IPA_RSRC_GRP_TYPE_RX_MAX][IPA_GROUP_MAX] = { [IPA_3_0] = { - /* UL DL DIAG DMA Unused uC Rx */ + /* UL DL DIAG DMA unused uC Rx */ [IPA_RSRC_GRP_TYPE_RX_HPS_CMDQ] = { {16, 16}, {24, 24}, {8, 8}, {8, 8}, {0, 0}, {8, 8} }, }, @@ -499,7 +498,7 @@ static const struct rsrc_min_max ipa3_rsrc_rx_grp_config {3, 3}, {7, 7}, {0, 0}, {2, 2}, {0, 0}, {0, 0} }, }, [IPA_4_0] = { - /* LWA_DL UL_DL not used UC_RX_Q, other are invalid */ + /* LWA_DL UL_DL unused UC_RX_Q, other are invalid */ [IPA_RSRC_GRP_TYPE_RX_HPS_CMDQ] = { {3, 3}, {7, 7}, {0, 0}, {2, 2}, {0, 0}, {0, 0} }, }, @@ -509,7 +508,7 @@ static const struct rsrc_min_max ipa3_rsrc_rx_grp_config { 3, 3 }, { 7, 7 }, { 2, 2 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }, }, [IPA_4_1] = { - /* LWA_DL UL_DL not used UC_RX_Q, other are invalid */ + /* LWA_DL UL_DL unused UC_RX_Q, other are invalid */ [IPA_RSRC_GRP_TYPE_RX_HPS_CMDQ] = { {3, 3}, {7, 7}, {0, 0}, {2, 2}, {0, 0}, {0, 0} }, }, @@ -519,14 +518,12 @@ static const struct rsrc_min_max ipa3_rsrc_rx_grp_config {4, 4}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} }, }, [IPA_4_5] = { - /* not used UL_DL not used not used UC_RX_Q - * other are invalid - */ + /* unused UL_DL unused unused UC_RX_Q N/A */ [IPA_RSRC_GRP_TYPE_RX_HPS_CMDQ] = { {0, 0}, {3, 3}, {0, 0}, {0, 0}, {0, 0}, {0, 0} }, }, [IPA_4_5_MHI] = { - /* PCIE DDR DMA QDSS not used other are invalid */ + /* PCIE DDR DMA QDSS unused N/A */ [IPA_RSRC_GRP_TYPE_RX_HPS_CMDQ] = { { 3, 3 }, {3, 3}, {3, 3}, {3, 3}, {0, 0}, { 0, 0 } }, }, @@ -536,7 +533,7 @@ static const struct rsrc_min_max ipa3_rsrc_rx_grp_config static const u32 ipa3_rsrc_rx_grp_hps_weight_config [IPA_VER_MAX][IPA_RSRC_GRP_TYPE_RX_HPS_WEIGHT_MAX][IPA_GROUP_MAX] = { [IPA_3_0] = { - /* UL DL DIAG DMA Unused uC Rx */ + /* UL DL DIAG DMA unused uC Rx */ [IPA_RSRC_GRP_TYPE_RX_HPS_WEIGHT_CONFIG] = { 0, 0, 0, 0, 0, 0 }, }, [IPA_3_5] = { @@ -552,7 +549,7 @@ static const u32 ipa3_rsrc_rx_grp_hps_weight_config [IPA_RSRC_GRP_TYPE_RX_HPS_WEIGHT_CONFIG] = { 1, 1, 1, 1, 0, 0 }, }, [IPA_4_0] = { - /* LWA_DL UL_DL not used UC_RX_Q, other are invalid */ + /* LWA_DL UL_DL unused UC_RX_Q N/A */ [IPA_RSRC_GRP_TYPE_RX_HPS_WEIGHT_CONFIG] = { 1, 1, 1, 1, 0, 0 }, }, [IPA_4_0_MHI] = { @@ -560,7 +557,7 @@ static const u32 ipa3_rsrc_rx_grp_hps_weight_config [IPA_RSRC_GRP_TYPE_RX_HPS_WEIGHT_CONFIG] = { 3, 5, 1, 1, 0, 0 }, }, [IPA_4_1] = { - /* LWA_DL UL_DL not used UC_RX_Q, other are invalid */ + /* LWA_DL UL_DL unused UC_RX_Q, other are invalid */ [IPA_RSRC_GRP_TYPE_RX_HPS_WEIGHT_CONFIG] = { 1, 1, 1, 1, 0, 0 }, }, }; @@ -2043,165 +2040,165 @@ static const struct ipa_ep_configuration ipa3_ep_mapping /* IPA_4_5 */ [IPA_4_5][IPA_CLIENT_WLAN1_PROD] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_SRC, true, IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP, QMB_MASTER_SELECT_DDR, { 9, 12, 8, 16, IPA_EE_AP, GSI_SMART_PRE_FETCH, 4 } }, [IPA_4_5][IPA_CLIENT_USB_PROD] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_SRC, true, IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP, QMB_MASTER_SELECT_DDR, { 0, 11, 8, 16, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY, 0 } }, [IPA_4_5][IPA_CLIENT_APPS_LAN_PROD] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_SRC, false, IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, QMB_MASTER_SELECT_DDR, { 11, 14, 10, 16, IPA_EE_AP, GSI_SMART_PRE_FETCH, 2 } }, [IPA_4_5][IPA_CLIENT_APPS_WAN_PROD] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_SRC, true, IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP, QMB_MASTER_SELECT_DDR, { 2, 7, 16, 32, IPA_EE_AP, GSI_SMART_PRE_FETCH, 8 } }, [IPA_4_5][IPA_CLIENT_APPS_CMD_PROD] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_SRC, false, IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY, QMB_MASTER_SELECT_DDR, { 7, 9, 20, 24, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY, 0 } }, [IPA_4_5][IPA_CLIENT_ODU_PROD] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_SRC, true, IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP, QMB_MASTER_SELECT_DDR, { 1, 0, 16, 20, IPA_EE_AP, GSI_SMART_PRE_FETCH, 4 } }, [IPA_4_5][IPA_CLIENT_ETHERNET_PROD] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_SRC, true, IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP, QMB_MASTER_SELECT_DDR, { 12, 0, 8, 16, IPA_EE_UC, GSI_SMART_PRE_FETCH, 4 } }, [IPA_4_5][IPA_CLIENT_Q6_WAN_PROD] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_SRC, true, IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_DEC_UCP, QMB_MASTER_SELECT_DDR, { 5, 0, 16, 28, IPA_EE_Q6, GSI_SMART_PRE_FETCH, 8 } }, [IPA_4_5][IPA_CLIENT_Q6_CMD_PROD] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_SRC, false, IPA_DPS_HPS_SEQ_TYPE_PKT_PROCESS_NO_DEC_UCP, QMB_MASTER_SELECT_DDR, { 6, 1, 20, 24, IPA_EE_Q6, GSI_SMART_PRE_FETCH, 8 } }, [IPA_4_5][IPA_CLIENT_Q6_DL_NLO_DATA_PROD] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_SRC, true, IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_DEC_UCP, QMB_MASTER_SELECT_DDR, { 8, 2, 27, 32, IPA_EE_Q6, GSI_FREE_PRE_FETCH, 3 } }, /* Only for test purpose */ [IPA_4_5][IPA_CLIENT_TEST_PROD] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_SRC, true, IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, QMB_MASTER_SELECT_DDR, { 0, 11, 8, 16, IPA_EE_AP } }, [IPA_4_5][IPA_CLIENT_TEST1_PROD] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_SRC, true, IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, QMB_MASTER_SELECT_DDR, { 0, 11, 8, 16, IPA_EE_AP } }, [IPA_4_5][IPA_CLIENT_TEST2_PROD] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_SRC, true, IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, QMB_MASTER_SELECT_DDR, { 1, 0, 8, 16, IPA_EE_AP } }, [IPA_4_5][IPA_CLIENT_TEST3_PROD] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_SRC, true, IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, QMB_MASTER_SELECT_DDR, { 9, 12, 8, 16, IPA_EE_AP } }, [IPA_4_5][IPA_CLIENT_TEST4_PROD] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_SRC, true, IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, QMB_MASTER_SELECT_DDR, { 11, 14, 8, 16, IPA_EE_AP } }, [IPA_4_5][IPA_CLIENT_WLAN1_CONS] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_DST, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, { 24, 3, 8, 14, IPA_EE_AP, GSI_SMART_PRE_FETCH, 4 } }, [IPA_4_5][IPA_CLIENT_USB_CONS] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_DST, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, { 25, 16, 9, 9, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY, 0 } }, [IPA_4_5][IPA_CLIENT_USB_DPL_CONS] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_DST, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, { 15, 15, 5, 5, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY, 0 } }, [IPA_4_5][IPA_CLIENT_APPS_LAN_CONS] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_DST, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, { 16, 10, 9, 9, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY, 0 } }, [IPA_4_5][IPA_CLIENT_APPS_WAN_CONS] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_DST, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, { 14, 1, 9, 9, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY, 0 } }, [IPA_4_5][IPA_CLIENT_ODU_EMB_CONS] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_DST, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, { 23, 8, 9, 9, IPA_EE_AP, GSI_SMART_PRE_FETCH, 4 } }, [IPA_4_5][IPA_CLIENT_ETHERNET_CONS] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_DST, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, { 28, 1, 9, 9, IPA_EE_UC } }, [IPA_4_5][IPA_CLIENT_Q6_LAN_CONS] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_DST, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, { 17, 3, 9, 9, IPA_EE_Q6, GSI_ESCAPE_BUF_ONLY, 0 } }, [IPA_4_5][IPA_CLIENT_Q6_WAN_CONS] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_DST, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, { 21, 7, 9, 9, IPA_EE_Q6, GSI_ESCAPE_BUF_ONLY, 0 } }, [IPA_4_5][IPA_CLIENT_Q6_UL_NLO_DATA_CONS] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_DST, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, { 19, 5, 5, 5, IPA_EE_Q6, GSI_SMART_PRE_FETCH, 2 } }, [IPA_4_5][IPA_CLIENT_Q6_UL_NLO_ACK_CONS] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_DST, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, { 20, 6, 5, 5, IPA_EE_Q6, GSI_SMART_PRE_FETCH, 2 } }, [IPA_4_5][IPA_CLIENT_Q6_QBAP_STATUS_CONS] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_DST, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, @@ -2209,38 +2206,38 @@ static const struct ipa_ep_configuration ipa3_ep_mapping /* Only for test purpose */ /* MBIM aggregation test pipes should have the same QMB as USB_CONS */ [IPA_4_5][IPA_CLIENT_TEST_CONS] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_DST, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, { 14, 1, 9, 9, IPA_EE_AP } }, [IPA_4_5][IPA_CLIENT_TEST1_CONS] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_DST, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, { 14, 1, 9, 9, IPA_EE_AP } }, [IPA_4_5][IPA_CLIENT_TEST2_CONS] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_DST, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, { 24, 3, 8, 14, IPA_EE_AP } }, [IPA_4_5][IPA_CLIENT_TEST3_CONS] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_DST, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, { 25, 16, 9, 9, IPA_EE_AP } }, [IPA_4_5][IPA_CLIENT_TEST4_CONS] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_DST, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, { 27, 18, 9, 9, IPA_EE_AP } }, /* Dummy consumer (pipe 31) is used in L2TP rt rule */ [IPA_4_5][IPA_CLIENT_DUMMY_CONS] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_DST, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, @@ -2297,7 +2294,7 @@ static const struct ipa_ep_configuration ipa3_ep_mapping { 10, 13, 8, 16, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY, 0 } }, /* Only for test purpose */ [IPA_4_5_MHI][IPA_CLIENT_TEST_PROD] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_SRC, true, IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, QMB_MASTER_SELECT_DDR, @@ -2372,7 +2369,7 @@ static const struct ipa_ep_configuration ipa3_ep_mapping /* Dummy consumer (pipe 31) is used in L2TP rt rule */ [IPA_4_5_MHI][IPA_CLIENT_DUMMY_CONS] = { - true, IPA_v4_5_GROUP_UL_DL, + true, IPA_v4_5_GROUP_UL_DL_DST, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_DDR, @@ -2517,7 +2514,7 @@ static struct ipa3_mem_partition ipa_4_2_mem_part = { .modem_comp_decomp_ofst = 0x0, .modem_comp_decomp_size = 0x0, .modem_ofst = 0xbf0, - .modem_size = 0x100c, + .modem_size = 0x140c, .apps_v4_flt_hash_ofst = 0x1bfc, .apps_v4_flt_hash_size = 0x0, .apps_v4_flt_nhash_ofst = 0x1bfc, @@ -2537,8 +2534,8 @@ static struct ipa3_mem_partition ipa_4_2_mem_part = { .apps_v6_rt_hash_size = 0x0, .apps_v6_rt_nhash_ofst = 0x1bfc, .apps_v6_rt_nhash_size = 0x0, - .uc_descriptor_ram_ofst = 0x1c00, - .uc_descriptor_ram_size = 0x400, + .uc_descriptor_ram_ofst = 0x2000, + .uc_descriptor_ram_size = 0x0, .pdn_config_ofst = 0x9F8, .pdn_config_size = 0x50, .stats_quota_ofst = 0xa50, @@ -6366,7 +6363,7 @@ static void ipa3_write_rsrc_grp_type_reg(int group_index, if (src) { switch (group_index) { case IPA_v4_5_MHI_GROUP_PCIE: - case IPA_v4_5_GROUP_UL_DL: + case IPA_v4_5_GROUP_UL_DL_SRC: ipahal_write_reg_n_fields( IPA_SRC_RSRC_GRP_01_RSRC_TYPE_n, n, val); @@ -6390,8 +6387,8 @@ static void ipa3_write_rsrc_grp_type_reg(int group_index, } } else { switch (group_index) { - case IPA_v4_5_MHI_GROUP_PCIE: - case IPA_v4_5_GROUP_UL_DL: + case IPA_v4_5_GROUP_UL_DL_DST: + case IPA_v4_5_MHI_GROUP_DDR: ipahal_write_reg_n_fields( IPA_DST_RSRC_GRP_01_RSRC_TYPE_n, n, val); @@ -6721,6 +6718,15 @@ void ipa3_suspend_apps_pipes(bool suspend) 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); @@ -6740,9 +6746,6 @@ void ipa3_suspend_apps_pipes(bool suspend) } if (suspend) ipa3_gsi_poll_after_suspend(ep); - else if (!atomic_read(&ep->sys->curr_polling_state)) - gsi_config_channel_mode(ep->gsi_chan_hdl, - GSI_CHAN_MODE_CALLBACK); } ipa_ep_idx = ipa_get_ep_mapping(IPA_CLIENT_APPS_WAN_CONS); @@ -6755,6 +6758,14 @@ void ipa3_suspend_apps_pipes(bool suspend) 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); @@ -6774,9 +6785,6 @@ void ipa3_suspend_apps_pipes(bool suspend) } if (suspend) ipa3_gsi_poll_after_suspend(ep); - else if (!atomic_read(&ep->sys->curr_polling_state)) - gsi_config_channel_mode(ep->gsi_chan_hdl, - GSI_CHAN_MODE_CALLBACK); } } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c index 4237e1f7a726aacba80a1b0d43a668c9fe4a7676..db4eb65cada20149080d9d8b8e1b35ffce2a8bc2 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt.c @@ -44,7 +44,8 @@ * @flt_generate_eq: Generate flt equation attributes from rule attributes * @rt_parse_hw_rule: Parse rt rule read from H/W * @flt_parse_hw_rule: Parse flt rule read from H/W - * @eq_bitfield: Array of the bit fields of the support equations + * @eq_bitfield: Array of the bit fields of the support equations. + * 0xFF means the equation is not supported */ struct ipahal_fltrt_obj { bool support_hash; @@ -172,6 +173,9 @@ static int ipa_flt_parse_hw_rule_ipav4(u8 *addr, #define IPA_GET_RULE_EQ_BIT_PTRN(__eq) \ (BIT(ipahal_fltrt_objs[ipahal_ctx->hw_type].eq_bitfield[(__eq)])) +#define IPA_IS_RULE_EQ_VALID(__eq) \ + (ipahal_fltrt_objs[ipahal_ctx->hw_type].eq_bitfield[(__eq)] != 0xFF) + /* * ipa_fltrt_rule_generation_err_check() - check basic validity on the rule * attribs before starting building it @@ -489,6 +493,7 @@ static struct ipahal_fltrt_obj ipahal_fltrt_objs[IPA_HW_MAX] = { [IPA_IHL_OFFSET_EQ_16] = 13, [IPA_FL_EQ] = 14, [IPA_IS_FRAG] = 15, + [IPA_IS_PURE_ACK] = 0xFF, }, }, @@ -517,22 +522,23 @@ static struct ipahal_fltrt_obj ipahal_fltrt_objs[IPA_HW_MAX] = { ipa_rt_parse_hw_rule, ipa_flt_parse_hw_rule_ipav4, { - [IPA_TOS_EQ] = 0, - [IPA_PROTOCOL_EQ] = 1, - [IPA_TC_EQ] = 2, - [IPA_OFFSET_MEQ128_0] = 3, - [IPA_OFFSET_MEQ128_1] = 4, - [IPA_OFFSET_MEQ32_0] = 5, - [IPA_OFFSET_MEQ32_1] = 6, - [IPA_IHL_OFFSET_MEQ32_0] = 7, - [IPA_IHL_OFFSET_MEQ32_1] = 8, - [IPA_METADATA_COMPARE] = 9, - [IPA_IHL_OFFSET_RANGE16_0] = 10, - [IPA_IHL_OFFSET_RANGE16_1] = 11, - [IPA_IHL_OFFSET_EQ_32] = 12, - [IPA_IHL_OFFSET_EQ_16] = 13, - [IPA_FL_EQ] = 14, - [IPA_IS_FRAG] = 15, + [IPA_TOS_EQ] = 0, + [IPA_PROTOCOL_EQ] = 1, + [IPA_TC_EQ] = 2, + [IPA_OFFSET_MEQ128_0] = 3, + [IPA_OFFSET_MEQ128_1] = 4, + [IPA_OFFSET_MEQ32_0] = 5, + [IPA_OFFSET_MEQ32_1] = 6, + [IPA_IHL_OFFSET_MEQ32_0] = 7, + [IPA_IHL_OFFSET_MEQ32_1] = 8, + [IPA_METADATA_COMPARE] = 9, + [IPA_IHL_OFFSET_RANGE16_0] = 10, + [IPA_IHL_OFFSET_RANGE16_1] = 11, + [IPA_IHL_OFFSET_EQ_32] = 12, + [IPA_IHL_OFFSET_EQ_16] = 13, + [IPA_FL_EQ] = 14, + [IPA_IS_FRAG] = 15, + [IPA_IS_PURE_ACK] = 0xFF, }, }, @@ -561,22 +567,23 @@ static struct ipahal_fltrt_obj ipahal_fltrt_objs[IPA_HW_MAX] = { ipa_rt_parse_hw_rule, ipa_flt_parse_hw_rule_ipav4, { - [IPA_TOS_EQ] = 0, - [IPA_PROTOCOL_EQ] = 1, - [IPA_TC_EQ] = 2, - [IPA_OFFSET_MEQ128_0] = 3, - [IPA_OFFSET_MEQ128_1] = 4, - [IPA_OFFSET_MEQ32_0] = 5, - [IPA_OFFSET_MEQ32_1] = 6, - [IPA_IHL_OFFSET_MEQ32_0] = 7, - [IPA_IHL_OFFSET_MEQ32_1] = 8, - [IPA_METADATA_COMPARE] = 9, - [IPA_IHL_OFFSET_RANGE16_0] = 10, - [IPA_IHL_OFFSET_RANGE16_1] = 11, - [IPA_IHL_OFFSET_EQ_32] = 12, - [IPA_IHL_OFFSET_EQ_16] = 13, - [IPA_FL_EQ] = 14, - [IPA_IS_FRAG] = 15, + [IPA_TOS_EQ] = 0, + [IPA_PROTOCOL_EQ] = 1, + [IPA_TC_EQ] = 2, + [IPA_OFFSET_MEQ128_0] = 3, + [IPA_OFFSET_MEQ128_1] = 4, + [IPA_OFFSET_MEQ32_0] = 5, + [IPA_OFFSET_MEQ32_1] = 6, + [IPA_IHL_OFFSET_MEQ32_0] = 7, + [IPA_IHL_OFFSET_MEQ32_1] = 8, + [IPA_METADATA_COMPARE] = 9, + [IPA_IHL_OFFSET_RANGE16_0] = 10, + [IPA_IHL_OFFSET_RANGE16_1] = 11, + [IPA_IHL_OFFSET_EQ_32] = 12, + [IPA_IHL_OFFSET_EQ_16] = 13, + [IPA_FL_EQ] = 14, + [IPA_IS_FRAG] = 15, + [IPA_IS_PURE_ACK] = 0xFF, }, }, @@ -605,22 +612,23 @@ static struct ipahal_fltrt_obj ipahal_fltrt_objs[IPA_HW_MAX] = { ipa_rt_parse_hw_rule, ipa_flt_parse_hw_rule_ipav4, { - [IPA_TOS_EQ] = 0, - [IPA_PROTOCOL_EQ] = 1, - [IPA_TC_EQ] = 2, - [IPA_OFFSET_MEQ128_0] = 3, - [IPA_OFFSET_MEQ128_1] = 4, - [IPA_OFFSET_MEQ32_0] = 5, - [IPA_OFFSET_MEQ32_1] = 6, - [IPA_IHL_OFFSET_MEQ32_0] = 7, - [IPA_IHL_OFFSET_MEQ32_1] = 8, - [IPA_METADATA_COMPARE] = 9, - [IPA_IHL_OFFSET_RANGE16_0] = 10, - [IPA_IHL_OFFSET_RANGE16_1] = 11, - [IPA_IHL_OFFSET_EQ_32] = 12, - [IPA_IHL_OFFSET_EQ_16] = 13, - [IPA_FL_EQ] = 14, - [IPA_IS_FRAG] = 15, + [IPA_TOS_EQ] = 0xFF, + [IPA_PROTOCOL_EQ] = 1, + [IPA_TC_EQ] = 2, + [IPA_OFFSET_MEQ128_0] = 3, + [IPA_OFFSET_MEQ128_1] = 4, + [IPA_OFFSET_MEQ32_0] = 5, + [IPA_OFFSET_MEQ32_1] = 6, + [IPA_IHL_OFFSET_MEQ32_0] = 7, + [IPA_IHL_OFFSET_MEQ32_1] = 8, + [IPA_METADATA_COMPARE] = 9, + [IPA_IHL_OFFSET_RANGE16_0] = 10, + [IPA_IHL_OFFSET_RANGE16_1] = 11, + [IPA_IHL_OFFSET_EQ_32] = 12, + [IPA_IHL_OFFSET_EQ_16] = 13, + [IPA_FL_EQ] = 14, + [IPA_IS_FRAG] = 15, + [IPA_IS_PURE_ACK] = 0, }, }, }; @@ -696,10 +704,25 @@ static int ipa_fltrt_generate_hw_rule_bdy_ip4(u16 *en_rule, u8 ihl_ofst_meq32 = 0; u8 ofst_meq128 = 0; int rc = 0; + bool tos_done = false; + + if (attrib->attrib_mask & IPA_FLT_IS_PURE_ACK) { + if (!IPA_IS_RULE_EQ_VALID(IPA_IS_PURE_ACK)) { + IPAHAL_ERR("is_pure_ack eq not supported\n"); + goto err; + } + *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_IS_PURE_ACK); + extra = ipa_write_8(0, extra); + } - if (attrib->attrib_mask & IPA_FLT_TOS) { - *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_TOS_EQ); - extra = ipa_write_8(attrib->u.v4.tos, extra); + if (attrib->attrib_mask & IPA_FLT_TOS && !tos_done) { + if (!IPA_IS_RULE_EQ_VALID(IPA_TOS_EQ)) { + IPAHAL_DBG("tos eq not supported\n"); + } else { + *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_TOS_EQ); + extra = ipa_write_8(attrib->u.v4.tos, extra); + tos_done = true; + } } if (attrib->attrib_mask & IPA_FLT_PROTOCOL) { @@ -790,7 +813,7 @@ static int ipa_fltrt_generate_hw_rule_bdy_ip4(u16 *en_rule, } *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN( ipa3_0_ofst_meq32[ofst_meq32]); - /* 0 => offset of TOS in v4 header */ + /* 0 => Take the first word. offset of TOS in v4 header is 1 */ extra = ipa_write_8(0, extra); rest = ipa_write_32((attrib->tos_mask << 16), rest); rest = ipa_write_32((attrib->tos_value << 16), rest); @@ -841,6 +864,24 @@ static int ipa_fltrt_generate_hw_rule_bdy_ip4(u16 *en_rule, ofst_meq32++; } + if (attrib->attrib_mask & IPA_FLT_TOS && !tos_done) { + if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq32, ofst_meq32)) { + IPAHAL_DBG("ran out of meq32 eq\n"); + } else { + *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN( + ipa3_0_ofst_meq32[ofst_meq32]); + /* + * 0 => Take the first word. + * offset of TOS in v4 header is 1 + */ + extra = ipa_write_8(0, extra); + rest = ipa_write_32(0xFF << 16, rest); + rest = ipa_write_32((attrib->u.v4.tos << 16), rest); + ofst_meq32++; + tos_done = true; + } + } + if (attrib->attrib_mask & IPA_FLT_TYPE) { if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32, ihl_ofst_meq32)) { @@ -933,6 +974,26 @@ static int ipa_fltrt_generate_hw_rule_bdy_ip4(u16 *en_rule, ihl_ofst_meq32++; } + if (attrib->attrib_mask & IPA_FLT_TOS && !tos_done) { + if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32, + ihl_ofst_meq32)) { + IPAHAL_DBG("ran out of ihl_meq32 eq\n"); + } else { + *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN( + ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]); + /* + * 0 => Take the first word. offset of TOS in + * v4 header is 1. MSB bit asserted at IHL means + * to ignore packet IHL and do offset inside IPA header + */ + extra = ipa_write_8(0x80, extra); + rest = ipa_write_32(0xFF << 16, rest); + rest = ipa_write_32((attrib->u.v4.tos << 16), rest); + ihl_ofst_meq32++; + tos_done = true; + } + } + if (attrib->attrib_mask & IPA_FLT_META_DATA) { *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_METADATA_COMPARE); rest = ipa_write_32(attrib->meta_data_mask, rest); @@ -1010,6 +1071,11 @@ static int ipa_fltrt_generate_hw_rule_bdy_ip4(u16 *en_rule, if (attrib->attrib_mask & IPA_FLT_FRAGMENT) *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_IS_FRAG); + if (attrib->attrib_mask & IPA_FLT_TOS && !tos_done) { + IPAHAL_ERR("could not find equation for tos\n"); + goto err; + } + goto done; err: @@ -1033,6 +1099,14 @@ static int ipa_fltrt_generate_hw_rule_bdy_ip6(u16 *en_rule, int rc = 0; /* v6 code below assumes no extension headers TODO: fix this */ + if (attrib->attrib_mask & IPA_FLT_IS_PURE_ACK) { + if (!IPA_IS_RULE_EQ_VALID(IPA_IS_PURE_ACK)) { + IPAHAL_ERR("is_pure_ack eq not supported\n"); + goto err; + } + *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_IS_PURE_ACK); + extra = ipa_write_8(0, extra); + } if (attrib->attrib_mask & IPA_FLT_NEXT_HDR) { *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_PROTOCOL_EQ); @@ -1597,6 +1671,12 @@ static int ipa_fltrt_calc_extra_wrd_bytes( { int num = 0; + /* + * tos_eq_present field has two meanings: + * tos equation for IPA ver < 4.5 (as the field name reveals) + * pure_ack equation for IPA ver >= 4.5 + * In both cases it needs one extra word. + */ if (attrib->tos_eq_present) num++; if (attrib->protocol_eq_present) @@ -1650,8 +1730,22 @@ static int ipa_fltrt_generate_hw_rule_bdy_from_eq( rest = *buf; } - if (attrib->tos_eq_present) - extra = ipa_write_8(attrib->tos_eq, extra); + /* + * tos_eq_present field has two meanings: + * tos equation for IPA ver < 4.5 (as the field name reveals) + * pure_ack equation for IPA ver >= 4.5 + * In both cases it needs one extra word. + */ + if (attrib->tos_eq_present) { + if (IPA_IS_RULE_EQ_VALID(IPA_IS_PURE_ACK)) { + extra = ipa_write_8(0, extra); + } else if (IPA_IS_RULE_EQ_VALID(IPA_TOS_EQ)) { + extra = ipa_write_8(attrib->tos_eq, extra); + } else { + IPAHAL_ERR("no support for pure_ack and tos eqs\n"); + return -EPERM; + } + } if (attrib->protocol_eq_present) extra = ipa_write_8(attrib->protocol_eq, extra); @@ -1807,11 +1901,31 @@ static int ipa_flt_generate_eq_ip4(enum ipa_ip_type ip, u8 ofst_meq128 = 0; u16 eq_bitmap = 0; u16 *en_rule = &eq_bitmap; + bool tos_done = false; - if (attrib->attrib_mask & IPA_FLT_TOS) { - *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_TOS_EQ); + if (attrib->attrib_mask & IPA_FLT_IS_PURE_ACK) { + if (!IPA_IS_RULE_EQ_VALID(IPA_IS_PURE_ACK)) { + IPAHAL_ERR("is_pure_ack eq not supported\n"); + return -EPERM; + } + *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_IS_PURE_ACK); + /* + * Starting IPA 4.5, where PURE ACK equation supported + * and TOS equation support removed, field tos_eq_present + * represent pure_ack presence. + */ eq_atrb->tos_eq_present = 1; - eq_atrb->tos_eq = attrib->u.v4.tos; + eq_atrb->tos_eq = 0; + } + + if (attrib->attrib_mask & IPA_FLT_TOS && !tos_done) { + if (!IPA_IS_RULE_EQ_VALID(IPA_TOS_EQ)) { + IPAHAL_DBG("tos eq not supported\n"); + } else { + *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_TOS_EQ); + eq_atrb->tos_eq_present = 1; + eq_atrb->tos_eq = attrib->u.v4.tos; + } } if (attrib->attrib_mask & IPA_FLT_PROTOCOL) { @@ -1993,6 +2107,26 @@ static int ipa_flt_generate_eq_ip4(enum ipa_ip_type ip, ofst_meq32++; } + if (attrib->attrib_mask & IPA_FLT_TOS && !tos_done) { + if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ofst_meq32, ofst_meq32)) { + IPAHAL_DBG("ran out of meq32 eq\n"); + } else { + *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN( + ipa3_0_ofst_meq32[ofst_meq32]); + /* + * offset 0 => Take the first word. + * offset of TOS in v4 header is 1 + */ + eq_atrb->offset_meq_32[ofst_meq32].offset = 0; + eq_atrb->offset_meq_32[ofst_meq32].mask = + 0xFF << 16; + eq_atrb->offset_meq_32[ofst_meq32].value = + attrib->u.v4.tos << 16; + ofst_meq32++; + tos_done = true; + } + } + if (attrib->attrib_mask & IPA_FLT_TYPE) { if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32, ihl_ofst_meq32)) { @@ -2039,6 +2173,29 @@ static int ipa_flt_generate_eq_ip4(enum ipa_ip_type ip, ihl_ofst_meq32++; } + if (attrib->attrib_mask & IPA_FLT_TOS && !tos_done) { + if (IPA_IS_RAN_OUT_OF_EQ(ipa3_0_ihl_ofst_meq32, + ihl_ofst_meq32)) { + IPAHAL_DBG("ran out of ihl_meq32 eq\n"); + } else { + *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN( + ipa3_0_ihl_ofst_meq32[ihl_ofst_meq32]); + /* + * 0 => Take the first word. offset of TOS in + * v4 header is 1. MSB bit asserted at IHL means + * to ignore packet IHL and do offset inside IPA header + */ + eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].offset = + 0x80; + eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].mask = + 0xFF << 16; + eq_atrb->ihl_offset_meq_32[ihl_ofst_meq32].value = + attrib->u.v4.tos << 16; + ihl_ofst_meq32++; + tos_done = true; + } + } + if (attrib->attrib_mask & IPA_FLT_META_DATA) { *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN( IPA_METADATA_COMPARE); @@ -2125,6 +2282,11 @@ static int ipa_flt_generate_eq_ip4(enum ipa_ip_type ip, eq_atrb->ipv4_frag_eq_present = 1; } + if (attrib->attrib_mask & IPA_FLT_TOS && !tos_done) { + IPAHAL_ERR("could not find equation for tos\n"); + return -EPERM; + } + eq_atrb->rule_eq_bitmap = *en_rule; eq_atrb->num_offset_meq_32 = ofst_meq32; eq_atrb->num_ihl_offset_range_16 = ihl_ofst_rng16; @@ -2145,6 +2307,21 @@ static int ipa_flt_generate_eq_ip6(enum ipa_ip_type ip, u16 eq_bitmap = 0; u16 *en_rule = &eq_bitmap; + if (attrib->attrib_mask & IPA_FLT_IS_PURE_ACK) { + if (!IPA_IS_RULE_EQ_VALID(IPA_IS_PURE_ACK)) { + IPAHAL_ERR("is_pure_ack eq not supported\n"); + return -EPERM; + } + *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN(IPA_IS_PURE_ACK); + /* + * Starting IPA 4.5, where PURE ACK equation supported + * and TOS equation support removed, field tos_eq_present + * represent pure_ack presenence. + */ + eq_atrb->tos_eq_present = 1; + eq_atrb->tos_eq = 0; + } + if (attrib->attrib_mask & IPA_FLT_NEXT_HDR) { *en_rule |= IPA_GET_RULE_EQ_BIT_PTRN( IPA_PROTOCOL_EQ); @@ -2658,8 +2835,19 @@ static int ipa_fltrt_parse_hw_rule_eq(u8 *addr, u32 hdr_sz, IPAHAL_DBG_LOW("eq_bitmap=0x%x\n", eq_bitmap); - if (eq_bitmap & IPA_GET_RULE_EQ_BIT_PTRN(IPA_TOS_EQ)) + if (IPA_IS_RULE_EQ_VALID(IPA_IS_PURE_ACK) && + (eq_bitmap & IPA_GET_RULE_EQ_BIT_PTRN(IPA_IS_PURE_ACK))) { + /* + * tos_eq_present field represents pure_ack when pure + * ack equation valid (started IPA 4.5). In this case + * tos equation should not be supported. + */ + atrb->tos_eq_present = true; + } + if (IPA_IS_RULE_EQ_VALID(IPA_TOS_EQ) && + (eq_bitmap & IPA_GET_RULE_EQ_BIT_PTRN(IPA_TOS_EQ))) { atrb->tos_eq_present = true; + } if (eq_bitmap & IPA_GET_RULE_EQ_BIT_PTRN(IPA_PROTOCOL_EQ)) atrb->protocol_eq_present = true; if (eq_bitmap & IPA_GET_RULE_EQ_BIT_PTRN(IPA_TC_EQ)) @@ -2715,8 +2903,12 @@ static int ipa_fltrt_parse_hw_rule_eq(u8 *addr, u32 hdr_sz, IPAHAL_DBG_LOW("addr=0x%pK extra=0x%pK rest=0x%pK\n", addr, extra, rest); - if (atrb->tos_eq_present) + if (IPA_IS_RULE_EQ_VALID(IPA_TOS_EQ) && atrb->tos_eq_present) atrb->tos_eq = *extra++; + if (IPA_IS_RULE_EQ_VALID(IPA_IS_PURE_ACK) && atrb->tos_eq_present) { + atrb->tos_eq = 0; + extra++; + } if (atrb->protocol_eq_present) atrb->protocol_eq = *extra++; if (atrb->tc_eq_present) @@ -2839,7 +3031,7 @@ static int ipa_rt_parse_hw_rule(u8 *addr, struct ipahal_rt_rule_entry *rule) IPAHAL_DBG_LOW("read hdr 0x%llx\n", rule_hdr->u.word); if (rule_hdr->u.word == 0) { - /* table termintator - empty table */ + /* table terminator - empty table */ rule->rule_size = 0; return 0; } @@ -2971,6 +3163,8 @@ int ipahal_fltrt_init(enum ipa_hw_type ipa_hw_type) int i; struct ipa_mem_buffer *mem; int rc = -EFAULT; + u32 eq_bits; + u8 *eq_bitfield; IPAHAL_DBG("Entry - HW_TYPE=%d\n", ipa_hw_type); @@ -3102,6 +3296,20 @@ int ipahal_fltrt_init(enum ipa_hw_type ipa_hw_type) } } + eq_bits = 0; + eq_bitfield = ipahal_fltrt_objs[ipa_hw_type].eq_bitfield; + for (i = 0; i < IPA_EQ_MAX; i++) { + if (!IPA_IS_RULE_EQ_VALID(i)) + continue; + + if (eq_bits & IPA_GET_RULE_EQ_BIT_PTRN(eq_bitfield[i])) { + IPAHAL_ERR("more than eq with same bit. eq=%d\n", i); + WARN_ON(1); + return -EFAULT; + } + eq_bits |= IPA_GET_RULE_EQ_BIT_PTRN(eq_bitfield[i]); + } + mem = &ipahal_ctx->empty_fltrt_tbl; /* setup an empty table in system memory; This will @@ -3735,14 +3943,14 @@ int ipahal_rt_generate_hw_rule(struct ipahal_rt_rule_gen_params *params, if (!tmp) return -ENOMEM; buf = tmp; - } else + } else { if ((long)buf & obj->rule_start_alignment) { - IPAHAL_ERR("buff is not rule rule start aligned\n"); + IPAHAL_ERR("buff is not rule start aligned\n"); return -EPERM; } + } - rc = ipahal_fltrt_objs[ipahal_ctx->hw_type].rt_generate_hw_rule( - params, hw_len, buf); + rc = obj->rt_generate_hw_rule(params, hw_len, buf); if (!tmp && !rc) { /* write the rule-set terminator */ memset(buf + *hw_len, 0, obj->tbl_width); @@ -3800,8 +4008,7 @@ int ipahal_flt_generate_hw_rule(struct ipahal_flt_rule_gen_params *params, return -EPERM; } - rc = ipahal_fltrt_objs[ipahal_ctx->hw_type].flt_generate_hw_rule( - params, hw_len, buf); + rc = obj->flt_generate_hw_rule(params, hw_len, buf); if (!tmp && !rc) { /* write the rule-set terminator */ memset(buf + *hw_len, 0, obj->tbl_width); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt_i.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt_i.h index 645383a8f1cf8948367d5d2e981ee1492b3ad892..681d08947555ca7c854e445b5a8c9b706949d58d 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_fltrt_i.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -36,6 +36,7 @@ enum ipa_fltrt_equations { IPA_IHL_OFFSET_EQ_16, IPA_FL_EQ, IPA_IS_FRAG, + IPA_IS_PURE_ACK, IPA_EQ_MAX, }; diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index d5b8656a17bb78ba268b6c6adc4acadd81833e4a..8d4406b10a6169e845a7dccb4be270ebcec02965 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -89,7 +89,6 @@ static void rmnet_ipa_get_stats_and_update(void); static int ipa3_wwan_add_ul_flt_rule_to_ipa(void); static int ipa3_wwan_del_ul_flt_rule_to_ipa(void); static void ipa3_wwan_msg_free_cb(void*, u32, u32); -static void ipa3_rmnet_rx_cb(void *priv); static int ipa3_rmnet_poll(struct napi_struct *napi, int budget); static void ipa3_wake_tx_queue(struct work_struct *work); @@ -1278,13 +1277,9 @@ static void apps_ipa_packet_receive_notify(void *priv, } dev->stats.rx_packets++; dev->stats.rx_bytes += packet_len; - } else if (evt == IPA_CLIENT_START_POLL) - ipa3_rmnet_rx_cb(priv); - else if (evt == IPA_CLIENT_COMP_NAPI) { - if (ipa3_rmnet_res.ipa_napi_enable) - napi_complete(&(rmnet_ipa3_ctx->wwan_priv->napi)); - } else + } else { IPAWANERR("Invalid evt %d received in wan_ipa_receive\n", evt); + } } static int handle3_ingress_format(struct net_device *dev, @@ -1341,7 +1336,8 @@ static int handle3_ingress_format(struct net_device *dev, ipa_wan_ep_cfg->notify = apps_ipa_packet_receive_notify; ipa_wan_ep_cfg->priv = dev; - ipa_wan_ep_cfg->napi_enabled = ipa3_rmnet_res.ipa_napi_enable; + if (ipa3_rmnet_res.ipa_napi_enable) + ipa_wan_ep_cfg->napi_obj = &(rmnet_ipa3_ctx->wwan_priv->napi); ipa_wan_ep_cfg->desc_fifo_sz = ipa3_rmnet_res.wan_rx_desc_size * IPA_FIFO_ELEMENT_SIZE; @@ -1967,11 +1963,11 @@ int ipa3_wwan_set_modem_perf_profile(int throughput) int ret; if (ipa3_ctx->use_ipa_pm) { - ret = ipa_pm_set_perf_profile(rmnet_ipa3_ctx->q6_pm_hdl, + ret = ipa_pm_set_throughput(rmnet_ipa3_ctx->q6_pm_hdl, throughput); if (ret) return ret; - ret = ipa_pm_set_perf_profile(rmnet_ipa3_ctx->q6_teth_pm_hdl, + ret = ipa_pm_set_throughput(rmnet_ipa3_ctx->q6_teth_pm_hdl, throughput); } else { memset(&profile, 0, sizeof(profile)); @@ -3638,6 +3634,13 @@ void ipa3_q6_handshake_complete(bool ssr_bootup) * SSR recovery */ rmnet_ipa_get_network_stats_and_update(); + } else { + /* + * To enable ipa power collapse we need to enable rpmh and uc + * handshake So that uc can do register retention. To enable + * this handshake we need to send the below message to rpmh + */ + ipa_pc_qmp_enable(); } imp_handle_modem_ready(); @@ -4184,12 +4187,6 @@ static void ipa3_wwan_msg_free_cb(void *buff, u32 len, u32 type) kfree(buff); } -static void ipa3_rmnet_rx_cb(void *priv) -{ - IPAWANDBG_LOW("\n"); - napi_schedule(&(rmnet_ipa3_ctx->wwan_priv->napi)); -} - static int ipa3_rmnet_poll(struct napi_struct *napi, int budget) { int rcvd_pkts = 0; diff --git a/drivers/platform/msm/ipa/test/ipa_pm_ut.c b/drivers/platform/msm/ipa/test/ipa_pm_ut.c index 305d199dfc25f8e1a9d309c5a910b2c6d1c4f707..c9545ccd34990f412d5abafc992be52447dcd433 100644 --- a/drivers/platform/msm/ipa/test/ipa_pm_ut.c +++ b/drivers/platform/msm/ipa/test/ipa_pm_ut.c @@ -1030,7 +1030,7 @@ static int ipa_pm_ut_deactivate_loop(void *priv) return -EFAULT; } - rc = ipa_pm_set_perf_profile(hdl_USB, 1200); + rc = ipa_pm_set_throughput(hdl_USB, 1200); if (rc) { IPA_UT_ERR("fail to set tput for client 1 rc = %d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail to set perf profile"); @@ -1044,7 +1044,7 @@ static int ipa_pm_ut_deactivate_loop(void *priv) return -EFAULT; } - rc = ipa_pm_set_perf_profile(hdl_WLAN, 800); + rc = ipa_pm_set_throughput(hdl_WLAN, 800); if (rc) { IPA_UT_ERR("fail to set tput for client 2 rc = %d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail to set perf profile"); @@ -1168,7 +1168,7 @@ static int ipa_pm_ut_set_perf_profile(void *priv) return -EFAULT; } - rc = ipa_pm_set_perf_profile(hdl_USB, 1200); + rc = ipa_pm_set_throughput(hdl_USB, 1200); if (rc) { IPA_UT_ERR("fail to set tput for client 1 rc = %d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail to set perf profile"); @@ -1182,7 +1182,7 @@ static int ipa_pm_ut_set_perf_profile(void *priv) return -EFAULT; } - rc = ipa_pm_set_perf_profile(hdl_WLAN, 800); + rc = ipa_pm_set_throughput(hdl_WLAN, 800); if (rc) { IPA_UT_ERR("fail to set tput for client 2 rc = %d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail to set perf profile"); @@ -1226,7 +1226,7 @@ static int ipa_pm_ut_set_perf_profile(void *priv) return -EINVAL; } - rc = ipa_pm_set_perf_profile(hdl_WLAN, 1200); + rc = ipa_pm_set_throughput(hdl_WLAN, 1200); if (rc) { IPA_UT_ERR("fail to set tput for client 2 rc = %d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail to set perf profile"); @@ -1297,14 +1297,14 @@ static int ipa_pm_ut_group_tput(void *priv) return -EFAULT; } - rc = ipa_pm_set_perf_profile(hdl_USB, 500); + rc = ipa_pm_set_throughput(hdl_USB, 500); if (rc) { IPA_UT_ERR("fail to set tput for client 1 rc = %d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail to set perf profile"); return -EFAULT; } - rc = ipa_pm_set_perf_profile(hdl_WLAN, 800); + rc = ipa_pm_set_throughput(hdl_WLAN, 800); if (rc) { IPA_UT_ERR("fail to set tput for client 2 rc = %d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail to set perf profile"); @@ -1355,7 +1355,7 @@ static int ipa_pm_ut_group_tput(void *priv) return -EFAULT; } - rc = ipa_pm_set_perf_profile(hdl_MODEM, 1000); + rc = ipa_pm_set_throughput(hdl_MODEM, 1000); if (rc) { IPA_UT_ERR("fail to set tput for client 2 rc = %d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail to set perf profile"); @@ -1464,14 +1464,14 @@ static int ipa_pm_ut_skip_clk_vote_tput(void *priv) return -EFAULT; } - rc = ipa_pm_set_perf_profile(hdl_USB, 1200); + rc = ipa_pm_set_throughput(hdl_USB, 1200); if (rc) { IPA_UT_ERR("fail to set tput for client 1 rc = %d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail to set perf profile"); return -EFAULT; } - rc = ipa_pm_set_perf_profile(hdl_WLAN, 800); + rc = ipa_pm_set_throughput(hdl_WLAN, 800); if (rc) { IPA_UT_ERR("fail to set tput for client 2 rc = %d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail to set perf profile"); @@ -1522,7 +1522,7 @@ static int ipa_pm_ut_skip_clk_vote_tput(void *priv) return -EFAULT; } - rc = ipa_pm_set_perf_profile(hdl_MODEM, 2000); + rc = ipa_pm_set_throughput(hdl_MODEM, 2000); if (rc) { IPA_UT_ERR("fail to set tput for client 2 rc = %d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail to set perf profile"); @@ -1631,14 +1631,14 @@ static int ipa_pm_ut_simple_exception(void *priv) return -EFAULT; } - rc = ipa_pm_set_perf_profile(hdl_USB, 1200); + rc = ipa_pm_set_throughput(hdl_USB, 1200); if (rc) { IPA_UT_ERR("fail to set tput for client 1 rc = %d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail to set perf profile"); return -EFAULT; } - rc = ipa_pm_set_perf_profile(hdl_WLAN, 2000); + rc = ipa_pm_set_throughput(hdl_WLAN, 2000); if (rc) { IPA_UT_ERR("fail to set tput for client 2 rc = %d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail to set perf profile"); @@ -1689,7 +1689,7 @@ static int ipa_pm_ut_simple_exception(void *priv) return -EFAULT; } - rc = ipa_pm_set_perf_profile(hdl_MODEM, 800); + rc = ipa_pm_set_throughput(hdl_MODEM, 800); if (rc) { IPA_UT_ERR("fail to set tput for client 2 rc = %d\n", rc); IPA_UT_TEST_FAIL_REPORT("fail to set perf profile"); diff --git a/drivers/platform/msm/qcom-geni-se.c b/drivers/platform/msm/qcom-geni-se.c index 9e9ebbbf29aa311318ee0289e92b817053ff1682..0d503e2e893293da242676308ce4220842286436 100644 --- a/drivers/platform/msm/qcom-geni-se.c +++ b/drivers/platform/msm/qcom-geni-se.c @@ -1440,6 +1440,15 @@ static int geni_se_probe(struct platform_device *pdev) struct resource *res; struct geni_se_device *geni_se_dev; + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (ret) { + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(&pdev->dev, "could not set DMA mask\n"); + return ret; + } + } + if (of_device_is_compatible(dev->of_node, "qcom,qupv3-geni-se-cb")) return geni_se_iommu_probe(dev); diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c index 4eb8e1a472b23821280fae17f91df35a8ce8737e..e335b18da20fc8ccc3264f20b5cdb883d4149580 100644 --- a/drivers/platform/x86/alienware-wmi.c +++ b/drivers/platform/x86/alienware-wmi.c @@ -519,6 +519,7 @@ static acpi_status alienware_wmax_command(struct wmax_basic_args *in_args, if (obj && obj->type == ACPI_TYPE_INTEGER) *out_data = (u32) obj->integer.value; } + kfree(output.pointer); return status; } diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 5269a01d9bdd9fa069541dfec40200be3601f714..a6a33327f5e7f79f776b9fb61bfdcb70ac6a5f83 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -487,6 +487,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = { { KE_KEY, 0xC4, { KEY_KBDILLUMUP } }, { KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } }, { KE_IGNORE, 0xC6, }, /* Ambient Light Sensor notification */ + { KE_KEY, 0xFA, { KEY_PROG2 } }, /* Lid flip action */ { KE_END, 0}, }; diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index fe98d4ac0df37040c3da8ad470bf7a33c5477fbe..e1e7e587b45b57e65deaf32397f3b2af5defa760 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -1097,10 +1097,10 @@ static const struct dmi_system_id no_hw_rfkill_list[] = { }, }, { - .ident = "Lenovo Legion Y520-15IKBN", + .ident = "Lenovo Legion Y520-15IKB", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y520-15IKBN"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y520-15IKB"), }, }, { diff --git a/drivers/platform/x86/intel_punit_ipc.c b/drivers/platform/x86/intel_punit_ipc.c index b5b890127479f8f586880762828bbd447a383ddf..b7dfe06261f1e6441644aebae16f8d2d6163b842 100644 --- a/drivers/platform/x86/intel_punit_ipc.c +++ b/drivers/platform/x86/intel_punit_ipc.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index bb1dcd7fbdeb81902f8b9a395569d1101c342fae..8221e000c8c23616d5206694f87e1f8d2c4a8665 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -34,6 +34,7 @@ #define TOSHIBA_ACPI_VERSION "0.24" #define PROC_INTERFACE_VERSION 1 +#include #include #include #include @@ -1682,7 +1683,7 @@ static const struct file_operations keys_proc_fops = { .write = keys_proc_write, }; -static int version_proc_show(struct seq_file *m, void *v) +static int __maybe_unused version_proc_show(struct seq_file *m, void *v) { seq_printf(m, "driver: %s\n", TOSHIBA_ACPI_VERSION); seq_printf(m, "proc_interface: %d\n", PROC_INTERFACE_VERSION); diff --git a/drivers/power/reset/vexpress-poweroff.c b/drivers/power/reset/vexpress-poweroff.c index 102f95a094603ff4c0b54245c6d79c50e764cab0..e9e749f87517d871cf2d4113568a44fb9c0b5d09 100644 --- a/drivers/power/reset/vexpress-poweroff.c +++ b/drivers/power/reset/vexpress-poweroff.c @@ -35,6 +35,7 @@ static void vexpress_reset_do(struct device *dev, const char *what) } static struct device *vexpress_power_off_device; +static atomic_t vexpress_restart_nb_refcnt = ATOMIC_INIT(0); static void vexpress_power_off(void) { @@ -99,10 +100,13 @@ static int _vexpress_register_restart_handler(struct device *dev) int err; vexpress_restart_device = dev; - err = register_restart_handler(&vexpress_restart_nb); - if (err) { - dev_err(dev, "cannot register restart handler (err=%d)\n", err); - return err; + if (atomic_inc_return(&vexpress_restart_nb_refcnt) == 1) { + err = register_restart_handler(&vexpress_restart_nb); + if (err) { + dev_err(dev, "cannot register restart handler (err=%d)\n", err); + atomic_dec(&vexpress_restart_nb_refcnt); + return err; + } } device_create_file(dev, &dev_attr_active); diff --git a/drivers/power/supply/axp288_charger.c b/drivers/power/supply/axp288_charger.c index 9dc7590e07cbe97795406b9810544f95faa2ae2a..4d016fbc3527ccfb447fdc91543d98757f540ea1 100644 --- a/drivers/power/supply/axp288_charger.c +++ b/drivers/power/supply/axp288_charger.c @@ -771,7 +771,7 @@ static int charger_init_hw_regs(struct axp288_chrg_info *info) } /* Determine charge current limit */ - cc = (ret & CHRG_CCCV_CC_MASK) >> CHRG_CCCV_CC_BIT_POS; + cc = (val & CHRG_CCCV_CC_MASK) >> CHRG_CCCV_CC_BIT_POS; cc = (cc * CHRG_CCCV_CC_LSB_RES) + CHRG_CCCV_CC_OFFSET; info->cc = cc; diff --git a/drivers/power/supply/generic-adc-battery.c b/drivers/power/supply/generic-adc-battery.c index 37e523374fe00ebe44de3f20ae12a1b8674641b5..371b5ec700870f0b3bc23f62ed939fc717644185 100644 --- a/drivers/power/supply/generic-adc-battery.c +++ b/drivers/power/supply/generic-adc-battery.c @@ -243,10 +243,10 @@ static int gab_probe(struct platform_device *pdev) struct power_supply_desc *psy_desc; struct power_supply_config psy_cfg = {}; struct gab_platform_data *pdata = pdev->dev.platform_data; - enum power_supply_property *properties; int ret = 0; int chan; - int index = 0; + int index = ARRAY_SIZE(gab_props); + bool any = false; adc_bat = devm_kzalloc(&pdev->dev, sizeof(*adc_bat), GFP_KERNEL); if (!adc_bat) { @@ -280,8 +280,6 @@ static int gab_probe(struct platform_device *pdev) } memcpy(psy_desc->properties, gab_props, sizeof(gab_props)); - properties = (enum power_supply_property *) - ((char *)psy_desc->properties + sizeof(gab_props)); /* * getting channel from iio and copying the battery properties @@ -295,15 +293,22 @@ static int gab_probe(struct platform_device *pdev) adc_bat->channel[chan] = NULL; } else { /* copying properties for supported channels only */ - memcpy(properties + sizeof(*(psy_desc->properties)) * index, - &gab_dyn_props[chan], - sizeof(gab_dyn_props[chan])); - index++; + int index2; + + for (index2 = 0; index2 < index; index2++) { + if (psy_desc->properties[index2] == + gab_dyn_props[chan]) + break; /* already known */ + } + if (index2 == index) /* really new */ + psy_desc->properties[index++] = + gab_dyn_props[chan]; + any = true; } } /* none of the channels are supported so let's bail out */ - if (index == 0) { + if (!any) { ret = -ENODEV; goto second_mem_fail; } @@ -314,7 +319,7 @@ static int gab_probe(struct platform_device *pdev) * as come channels may be not be supported by the device.So * we need to take care of that. */ - psy_desc->num_properties = ARRAY_SIZE(gab_props) + index; + psy_desc->num_properties = index; adc_bat->psy = power_supply_register(&pdev->dev, psy_desc, &psy_cfg); if (IS_ERR(adc_bat->psy)) { diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index b7b891a5da6c36ef6117421c58a6ee119290a38d..52a776b85d3e1210000d633c6bd2ae1ab9fe5afd 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -142,8 +143,13 @@ static void power_supply_deferred_register_work(struct work_struct *work) struct power_supply *psy = container_of(work, struct power_supply, deferred_register_work.work); - if (psy->dev.parent) - mutex_lock(&psy->dev.parent->mutex); + if (psy->dev.parent) { + while (!mutex_trylock(&psy->dev.parent->mutex)) { + if (psy->removing) + return; + msleep(10); + } + } psy_register_cooler(psy->dev.parent, psy); power_supply_changed(psy); @@ -1075,6 +1081,7 @@ EXPORT_SYMBOL_GPL(devm_power_supply_register_no_ws); void power_supply_unregister(struct power_supply *psy) { WARN_ON(atomic_dec_return(&psy->use_cnt)); + psy->removing = true; cancel_work_sync(&psy->changed_work); cancel_delayed_work_sync(&psy->deferred_register_work); sysfs_remove_link(&psy->dev.kobj, "powers"); diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index 3253ff859c3e17b980ff7d7c94d731477f6d8b75..bdbb9afd84fba57eac07400084066e3a2eaaa1f2 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -46,6 +46,7 @@ static const char * const power_supply_type_text[] = { "USB_PD", "USB_PD_DRP", "BrickID", "USB_HVDCP", "USB_HVDCP_3", "Wireless", "USB_FLOAT", "BMS", "Parallel", "Main", "Wipower", "USB_C_UFP", "USB_C_DFP", + "Charge_Pump", }; static const char * const power_supply_status_text[] = { @@ -385,6 +386,17 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(force_recharge), POWER_SUPPLY_ATTR(fcc_stepper_enable), POWER_SUPPLY_ATTR(toggle_stat), + POWER_SUPPLY_ATTR(main_fcc_max), + /* Charge pump properties */ + POWER_SUPPLY_ATTR(cp_status1), + POWER_SUPPLY_ATTR(cp_status2), + POWER_SUPPLY_ATTR(cp_enable), + POWER_SUPPLY_ATTR(cp_switcher_en), + POWER_SUPPLY_ATTR(cp_die_temp), + POWER_SUPPLY_ATTR(cp_isns), + POWER_SUPPLY_ATTR(cp_toggle_switcher), + POWER_SUPPLY_ATTR(cp_irq_status), + POWER_SUPPLY_ATTR(cp_ilim), /* Local extensions of type int64_t */ POWER_SUPPLY_ATTR(charge_counter_ext), /* Properties of type `const char *' */ diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index 66044ac593b71f292e1596e685183be828277b4c..e5e80d55a779653fb0f9f927b2c1de2285b3eaa4 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -92,6 +92,7 @@ struct pl_data { struct notifier_block nb; bool pl_disable; int taper_entry_fv; + int main_fcc_max; }; struct pl_data *the_chip; @@ -468,10 +469,16 @@ static void get_fcc_split(struct pl_data *chip, int total_ua, * through main charger's BATFET, keep the main charger's FCC * to the votable result. */ - if (chip->pl_batfet_mode == POWER_SUPPLY_PL_STACKED_BATFET) + if (chip->pl_batfet_mode == POWER_SUPPLY_PL_STACKED_BATFET) { *master_ua = max(0, total_ua); - else + if (chip->main_fcc_max) + *master_ua = min(*master_ua, + chip->main_fcc_max + *slave_ua); + } else { *master_ua = max(0, total_ua - *slave_ua); + if (chip->main_fcc_max) + *master_ua = min(*master_ua, chip->main_fcc_max); + } } static void get_fcc_stepper_params(struct pl_data *chip, int main_fcc_ua, @@ -1003,6 +1010,16 @@ static int pl_disable_vote_callback(struct votable *votable, chip->fcc_stepper_enable = pval.intval; pr_debug("FCC Stepper %s\n", pval.intval ? "enabled" : "disabled"); + rc = power_supply_get_property(chip->main_psy, + POWER_SUPPLY_PROP_MAIN_FCC_MAX, &pval); + if (rc < 0) { + pl_dbg(chip, PR_PARALLEL, + "Couldn't read primary charger FCC upper limit, rc=%d\n", + rc); + } else if (pval.intval > 0) { + chip->main_fcc_max = pval.intval; + } + if (chip->fcc_stepper_enable) { cancel_delayed_work_sync(&chip->fcc_stepper_work); vote(chip->pl_awake_votable, FCC_STEPPER_VOTER, false, 0); @@ -1148,6 +1165,10 @@ static int pl_disable_vote_callback(struct votable *votable, (master_fcc_ua * 100) / total_fcc_ua, (slave_fcc_ua * 100) / total_fcc_ua); } else { + if (chip->main_fcc_max) + total_fcc_ua = min(total_fcc_ua, + chip->main_fcc_max); + if (!chip->fcc_stepper_enable) { if (IS_USBIN(chip->pl_mode)) split_settled(chip); @@ -1242,6 +1263,8 @@ static bool is_parallel_available(struct pl_data *chip) if (!chip->pl_psy) return false; + vote(chip->pl_disable_votable, PARALLEL_PSY_VOTER, false, 0); + rc = power_supply_get_property(chip->pl_psy, POWER_SUPPLY_PROP_PARALLEL_MODE, &pval); if (rc < 0) { @@ -1290,8 +1313,6 @@ static bool is_parallel_available(struct pl_data *chip) if (!rc) chip->pl_fcc_max = pval.intval; - vote(chip->pl_disable_votable, PARALLEL_PSY_VOTER, false, 0); - return true; } diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h index 18f49fded5f8c17f8272d7495f9e0df3599903be..b6d7a56a9d8a08038bbe580c4b8c6b1acf084bfc 100644 --- a/drivers/power/supply/qcom/fg-core.h +++ b/drivers/power/supply/qcom/fg-core.h @@ -174,6 +174,8 @@ enum fg_sram_param_id { FG_SRAM_MONOTONIC_SOC, FG_SRAM_VOLTAGE_PRED, FG_SRAM_OCV, + FG_SRAM_VBAT_FINAL, + FG_SRAM_IBAT_FINAL, FG_SRAM_ESR, FG_SRAM_ESR_MDL, FG_SRAM_ESR_ACT, @@ -491,6 +493,8 @@ struct fg_dbgfs { extern int fg_decode_voltage_15b(struct fg_sram_param *sp, enum fg_sram_param_id id, int val); +extern int fg_decode_current_16b(struct fg_sram_param *sp, + enum fg_sram_param_id id, int val); extern int fg_decode_cc_soc(struct fg_sram_param *sp, enum fg_sram_param_id id, int value); extern int fg_decode_value_16b(struct fg_sram_param *sp, diff --git a/drivers/power/supply/qcom/fg-util.c b/drivers/power/supply/qcom/fg-util.c index 4d7894c94267c715d716a38660ed74c2f2166a46..82c453fe63a7ebbcc94e96125999566efabbd2c5 100644 --- a/drivers/power/supply/qcom/fg-util.c +++ b/drivers/power/supply/qcom/fg-util.c @@ -38,6 +38,16 @@ int fg_decode_voltage_15b(struct fg_sram_param *sp, return sp[id].value; } +int fg_decode_current_16b(struct fg_sram_param *sp, + enum fg_sram_param_id id, int value) +{ + value = sign_extend32(value, 15); + sp[id].value = div_s64((s64)value * sp[id].denmtr, sp[id].numrtr); + pr_debug("id: %d raw value: %x decoded value: %d\n", id, value, + sp[id].value); + return sp[id].value; +} + int fg_decode_cc_soc(struct fg_sram_param *sp, enum fg_sram_param_id id, int value) { diff --git a/drivers/power/supply/qcom/qg-core.h b/drivers/power/supply/qcom/qg-core.h index 575b77aa3d01c7b212549ff01f035fa765b75bbf..7063a4396cf8e35682b01bafdf6963190209aa8c 100644 --- a/drivers/power/supply/qcom/qg-core.h +++ b/drivers/power/supply/qcom/qg-core.h @@ -50,11 +50,13 @@ struct qg_dt { int delta_soc; int rbat_conn_mohm; int ignore_shutdown_soc_secs; + int shutdown_temp_diff; int cold_temp_threshold; int esr_qual_i_ua; int esr_qual_v_uv; int esr_disable_soc; int esr_min_ibat_ua; + int shutdown_soc_threshold; bool hold_soc_while_full; bool linearize_soc; bool cl_disable; diff --git a/drivers/power/supply/qcom/qpnp-fg-gen4.c b/drivers/power/supply/qcom/qpnp-fg-gen4.c index 1b47a1de06c8280ec7200268a56c70e867ea11ac..3390a8c1feae26fffb85867c18121cb9fe917e96 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen4.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen4.c @@ -32,7 +32,7 @@ #define FG_MEM_IF_PM8150B 0x0D #define FG_ADC_RR_PM8150B 0x13 -#define FG_SRAM_LEN 960 +#define FG_SRAM_LEN 972 #define PROFILE_LEN 416 #define PROFILE_COMP_LEN 24 #define KI_COEFF_SOC_LEVELS 3 @@ -119,6 +119,10 @@ #define CYCLE_COUNT_OFFSET 0 #define PROFILE_INTEGRITY_WORD 299 #define PROFILE_INTEGRITY_OFFSET 0 +#define IBAT_FINAL_WORD 320 +#define IBAT_FINAL_OFFSET 0 +#define VBAT_FINAL_WORD 321 +#define VBAT_FINAL_OFFSET 0 #define ESR_WORD 331 #define ESR_OFFSET 0 #define ESR_MDL_WORD 335 @@ -180,6 +184,7 @@ struct fg_dt_props { bool hold_soc_while_full; bool linearize_soc; bool rapid_soc_dec_en; + bool five_pin_battery; int cutoff_volt_mv; int empty_volt_mv; int cutoff_curr_ma; @@ -237,6 +242,7 @@ struct fg_gen4_chip { int esr_actual; int esr_nominal; int soh; + bool first_profile_load; bool ki_coeff_dischg_en; bool slope_limit_en; bool esr_fast_calib; @@ -246,6 +252,7 @@ struct fg_gen4_chip { bool esr_fcc_ctrl_en; bool rslow_low; bool rapid_soc_dec_en; + bool vbatt_low; }; struct bias_config { @@ -284,6 +291,10 @@ static struct fg_sram_param pm8150b_v1_sram_params[] = { 244141, 0, NULL, fg_decode_voltage_15b), PARAM(OCV, OCV_WORD, OCV_OFFSET, 2, 1000, 244141, 0, NULL, fg_decode_voltage_15b), + PARAM(VBAT_FINAL, VBAT_FINAL_WORD, VBAT_FINAL_OFFSET, 2, 1000, 244141, + 0, NULL, fg_decode_voltage_15b), + PARAM(IBAT_FINAL, IBAT_FINAL_WORD, IBAT_FINAL_OFFSET, 2, 1000, 488282, + 0, NULL, fg_decode_current_16b), PARAM(ESR, ESR_WORD, ESR_OFFSET, 2, 1000, 244141, 0, fg_encode_default, fg_decode_value_16b), PARAM(ESR_MDL, ESR_MDL_WORD, ESR_MDL_OFFSET, 2, 1000, 244141, 0, @@ -372,6 +383,10 @@ static struct fg_sram_param pm8150b_v2_sram_params[] = { 1000, 244141, 0, NULL, fg_decode_voltage_15b), PARAM(OCV, OCV_v2_WORD, OCV_v2_OFFSET, 2, 1000, 244141, 0, NULL, fg_decode_voltage_15b), + PARAM(VBAT_FINAL, VBAT_FINAL_WORD, VBAT_FINAL_OFFSET, 2, 1000, 244141, + 0, NULL, fg_decode_voltage_15b), + PARAM(IBAT_FINAL, IBAT_FINAL_WORD, IBAT_FINAL_OFFSET, 2, 1000, 488282, + 0, NULL, fg_decode_current_16b), PARAM(ESR, ESR_WORD, ESR_OFFSET, 2, 1000, 244141, 0, fg_encode_default, fg_decode_value_16b), PARAM(ESR_MDL, ESR_MDL_WORD, ESR_MDL_OFFSET, 2, 1000, 244141, 0, @@ -449,8 +464,6 @@ static struct fg_sram_param pm8150b_v2_sram_params[] = { 1, 1, 1, 0, fg_encode_default, NULL), }; -static bool is_batt_empty(struct fg_dev *fg); - /* All get functions below */ struct bias_config id_table[3] = { @@ -693,6 +706,51 @@ static bool is_debug_batt_id(struct fg_dev *fg) return false; } +static int fg_gen4_get_cell_impedance(struct fg_gen4_chip *chip, int *val) +{ + struct fg_dev *fg = &chip->fg; + int rc, esr_uohms, temp, vbat_term_mv, v_delta, rprot_uohms = 0; + + rc = fg_get_battery_resistance(fg, &esr_uohms); + if (rc < 0) + return rc; + + if (!chip->dt.five_pin_battery) + goto out; + + if (fg->charge_type != POWER_SUPPLY_CHARGE_TYPE_TAPER || + fg->bp.float_volt_uv <= 0) + goto out; + + rc = fg_get_battery_voltage(fg, &vbat_term_mv); + if (rc < 0) + goto out; + + rc = fg_get_sram_prop(fg, FG_SRAM_VBAT_FINAL, &temp); + if (rc < 0) { + pr_err("Error in getting VBAT_FINAL rc:%d\n", rc); + goto out; + } + + v_delta = abs(temp - fg->bp.float_volt_uv); + + rc = fg_get_sram_prop(fg, FG_SRAM_IBAT_FINAL, &temp); + if (rc < 0) { + pr_err("Error in getting IBAT_FINAL rc:%d\n", rc); + goto out; + } + + if (!temp) + goto out; + + rprot_uohms = div64_u64((u64)v_delta * 1000000, abs(temp)); + pr_debug("v_delta: %d ibat_final: %d rprot_uohms: %d\n", v_delta, temp, + rprot_uohms); +out: + *val = esr_uohms - rprot_uohms; + return rc; +} + static int fg_gen4_get_prop_capacity(struct fg_dev *fg, int *val) { struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg); @@ -713,7 +771,7 @@ static int fg_gen4_get_prop_capacity(struct fg_dev *fg, int *val) return 0; } - if (is_batt_empty(fg)) { + if (chip->vbatt_low) { *val = EMPTY_SOC; return 0; } @@ -812,7 +870,7 @@ static int fg_gen4_get_ttf_param(void *data, enum ttf_param param, int *val) *val = chip->dt.sys_term_curr_ma; break; case TTF_RBATT: - rc = fg_get_battery_resistance(fg, val); + rc = fg_gen4_get_cell_impedance(chip, val); break; case TTF_VFLOAT: *val = fg->bp.float_volt_uv; @@ -1759,6 +1817,13 @@ static void profile_load_work(struct work_struct *work) pr_err("Error in writing to ACT_BATT_CAP rc=%d\n", rc); } done: + rc = fg_sram_read(fg, PROFILE_INTEGRITY_WORD, + PROFILE_INTEGRITY_OFFSET, &val, 1, FG_IMA_DEFAULT); + if (!rc && (val & FIRST_PROFILE_LOAD_BIT)) { + fg_dbg(fg, FG_STATUS, "First profile load bit is set\n"); + chip->first_profile_load = true; + } + rc = fg_gen4_bp_params_config(fg); if (rc < 0) pr_err("Error in configuring battery profile params, rc:%d\n", @@ -2447,13 +2512,13 @@ static irqreturn_t fg_delta_esr_irq_handler(int irq, void *data) { struct fg_dev *fg = data; struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg); - int esr_mohms, rc; + int esr_uohms, rc; - rc = fg_get_battery_resistance(fg, &esr_mohms); + rc = fg_get_battery_resistance(fg, &esr_uohms); if (rc < 0) return IRQ_HANDLED; - fg_dbg(fg, FG_IRQ, "irq %d triggered esr_mohms: %d\n", irq, esr_mohms); + fg_dbg(fg, FG_IRQ, "irq %d triggered esr_uohms: %d\n", irq, esr_uohms); if (chip->esr_fast_calib) { vote(fg->awake_votable, ESR_CALIB, true, 0); @@ -2481,17 +2546,22 @@ static irqreturn_t fg_vbatt_low_irq_handler(int irq, void *data) fg_dbg(fg, FG_IRQ, "irq %d triggered vbatt_mv: %d msoc_raw:%d\n", irq, vbatt_mv, msoc_raw); - if (chip->dt.rapid_soc_dec_en && vbatt_mv < chip->dt.cutoff_volt_mv) { - /* - * Set this flag so that slope limiter coefficient cannot be - * configured during rapid SOC decrease. - */ - chip->rapid_soc_dec_en = true; + if (vbatt_mv < chip->dt.cutoff_volt_mv) { + if (chip->dt.rapid_soc_dec_en) { + /* + * Set this flag so that slope limiter coefficient + * cannot be configured during rapid SOC decrease. + */ + chip->rapid_soc_dec_en = true; - rc = fg_gen4_rapid_soc_config(chip, true); - if (rc < 0) - pr_err("Error in configuring for rapid SOC reduction rc:%d\n", - rc); + rc = fg_gen4_rapid_soc_config(chip, true); + if (rc < 0) + pr_err("Error in configuring for rapid SOC reduction rc:%d\n", + rc); + } else { + /* Set the flag to show 0% */ + chip->vbatt_low = true; + } } if (batt_psy_initialized(fg)) @@ -2675,13 +2745,14 @@ static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data) pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc); /* - * If ESR fast calibration is done without a delta ESR interrupt, then - * it is possibly a failed attempt. In such cases, retry ESR fast - * calibration once again. This will get restored to normal config once - * a delta ESR interrupt fires or the timer expires. + * If ESR fast calibration is done even before 3 delta ESR interrupts + * had fired, then it is possibly a failed attempt. In such cases, + * retry ESR fast calibration once again. This will get restored to + * normal config once the timer expires or delta ESR interrupt count + * reaches the threshold. */ if (chip->esr_fast_calib && chip->esr_fast_calib_done && - !chip->delta_esr_count && !chip->esr_fast_calib_retry) { + (chip->delta_esr_count < 3) && !chip->esr_fast_calib_retry) { rc = fg_gen4_esr_fast_calib_config(chip, true); if (rc < 0) pr_err("Error in configuring esr_fast_calib, rc=%d\n", @@ -2828,36 +2899,6 @@ static struct fg_irq_info fg_irqs[FG_GEN4_IRQ_MAX] = { }, }; -static bool is_batt_empty(struct fg_dev *fg) -{ - struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg); - u8 status; - int rc, vbatt_uv, msoc; - - rc = fg_read(fg, BATT_SOC_INT_RT_STS(fg), &status, 1); - if (rc < 0) { - pr_err("failed to read addr=0x%04x, rc=%d\n", - BATT_SOC_INT_RT_STS(fg), rc); - return false; - } - - if (!(status & MSOC_EMPTY_BIT)) - return false; - - rc = fg_get_battery_voltage(fg, &vbatt_uv); - if (rc < 0) { - pr_err("failed to get battery voltage, rc=%d\n", rc); - return false; - } - - rc = fg_get_msoc(fg, &msoc); - if (!rc) - pr_warn_ratelimited("batt_soc_rt_sts: %x vbatt: %d uV msoc:%d\n", - status, vbatt_uv, msoc); - - return ((vbatt_uv < chip->dt.cutoff_volt_mv * 1000) ? true : false); -} - static enum alarmtimer_restart fg_esr_fast_cal_timer(struct alarm *alarm, ktime_t time) { @@ -3360,6 +3401,9 @@ static int fg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_SOC_REPORTING_READY: pval->intval = fg->soc_reporting_ready; break; + case POWER_SUPPLY_PROP_CLEAR_SOH: + pval->intval = chip->first_profile_load; + break; case POWER_SUPPLY_PROP_SOH: pval->intval = chip->soh; break; @@ -3406,7 +3450,9 @@ static int fg_psy_set_property(struct power_supply *psy, const union power_supply_propval *pval) { struct fg_gen4_chip *chip = power_supply_get_drvdata(psy); + struct fg_dev *fg = &chip->fg; int rc = 0; + u8 val, mask; switch (psp) { case POWER_SUPPLY_PROP_CHARGE_FULL: @@ -3453,6 +3499,21 @@ static int fg_psy_set_property(struct power_supply *psy, case POWER_SUPPLY_PROP_SOH: chip->soh = pval->intval; break; + case POWER_SUPPLY_PROP_CLEAR_SOH: + if (chip->first_profile_load && !pval->intval) { + fg_dbg(fg, FG_STATUS, "Clearing first profile load bit\n"); + val = 0; + mask = FIRST_PROFILE_LOAD_BIT; + rc = fg_sram_masked_write(fg, PROFILE_INTEGRITY_WORD, + PROFILE_INTEGRITY_OFFSET, mask, val, + FG_IMA_DEFAULT); + if (rc < 0) + pr_err("Error in writing to profile integrity word rc=%d\n", + rc); + else + chip->first_profile_load = false; + } + break; default: break; } @@ -3470,6 +3531,7 @@ static int fg_property_is_writeable(struct power_supply *psy, case POWER_SUPPLY_PROP_ESR_ACTUAL: case POWER_SUPPLY_PROP_ESR_NOMINAL: case POWER_SUPPLY_PROP_SOH: + case POWER_SUPPLY_PROP_CLEAR_SOH: return 1; default: break; @@ -3498,6 +3560,7 @@ static enum power_supply_property fg_psy_props[] = { POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW, POWER_SUPPLY_PROP_CYCLE_COUNTS, POWER_SUPPLY_PROP_SOC_REPORTING_READY, + POWER_SUPPLY_PROP_CLEAR_SOH, POWER_SUPPLY_PROP_SOH, POWER_SUPPLY_PROP_DEBUG_BATTERY, POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, @@ -3881,18 +3944,14 @@ static int fg_gen4_hw_init(struct fg_gen4_chip *chip) } if (chip->dt.batt_temp_hyst != -EINVAL) { - if (chip->dt.batt_temp_cold_thresh != -EINVAL && - chip->dt.batt_temp_hot_thresh != -EINVAL) { - val = chip->dt.batt_temp_hyst & BATT_TEMP_HYST_MASK; - mask = BATT_TEMP_HYST_MASK; - rc = fg_sram_masked_write(fg, BATT_TEMP_CONFIG2_WORD, - BATT_TEMP_HYST_DELTA_OFFSET, mask, val, - FG_IMA_DEFAULT); - if (rc < 0) { - pr_err("Error in writing batt_temp_hyst, rc=%d\n", - rc); - return rc; - } + val = chip->dt.batt_temp_hyst & BATT_TEMP_HYST_MASK; + mask = BATT_TEMP_HYST_MASK; + rc = fg_sram_masked_write(fg, BATT_TEMP_CONFIG2_WORD, + BATT_TEMP_HYST_DELTA_OFFSET, mask, val, + FG_IMA_DEFAULT); + if (rc < 0) { + pr_err("Error in writing batt_temp_hyst, rc=%d\n", rc); + return rc; } } @@ -4275,8 +4334,8 @@ static int fg_parse_esr_cal_params(struct fg_dev *fg) #define DEFAULT_CL_MAX_DEC_DECIPERC 100 #define DEFAULT_CL_MIN_LIM_DECIPERC 0 #define DEFAULT_CL_MAX_LIM_DECIPERC 0 -#define BTEMP_DELTA_LOW 2 -#define BTEMP_DELTA_HIGH 10 +#define BTEMP_DELTA_LOW 0 +#define BTEMP_DELTA_HIGH 3 #define DEFAULT_ESR_PULSE_THRESH_MA 47 #define DEFAULT_ESR_MEAS_CURR_MA 120 static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) @@ -4492,13 +4551,13 @@ static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) rc = of_property_read_u32(node, "qcom,fg-batt-temp-hyst", &temp); if (rc < 0) chip->dt.batt_temp_hyst = -EINVAL; - else + else if (temp >= BTEMP_DELTA_LOW && temp <= BTEMP_DELTA_HIGH) chip->dt.batt_temp_hyst = temp; rc = of_property_read_u32(node, "qcom,fg-batt-temp-delta", &temp); if (rc < 0) chip->dt.batt_temp_delta = -EINVAL; - else if (temp > BTEMP_DELTA_LOW && temp <= BTEMP_DELTA_HIGH) + else if (temp >= BTEMP_DELTA_LOW && temp <= BTEMP_DELTA_HIGH) chip->dt.batt_temp_delta = temp; chip->dt.hold_soc_while_full = of_property_read_bool(node, @@ -4540,6 +4599,9 @@ static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) chip->dt.rapid_soc_dec_en = of_property_read_bool(node, "qcom,rapid-soc-dec-en"); + + chip->dt.five_pin_battery = of_property_read_bool(node, + "qcom,five-pin-battery"); return 0; } diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index d0e9d05e76b585d7447bffa41127e2a2c14e8ef6..866b976657dcbb43079d586d135992306d306872 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -2515,7 +2515,6 @@ static int qg_setup_battery(struct qpnp_qg *chip) return 0; } - static struct ocv_all ocv[] = { [S7_PON_OCV] = { 0, 0, "S7_PON_OCV"}, [S3_GOOD_OCV] = { 0, 0, "S3_GOOD_OCV"}, @@ -2529,7 +2528,8 @@ static int qg_determine_pon_soc(struct qpnp_qg *chip) int rc = 0, batt_temp = 0, i; bool use_pon_ocv = true; unsigned long rtc_sec = 0; - u32 ocv_uv = 0, soc = 0, shutdown[SDAM_MAX] = {0}; + u32 ocv_uv = 0, soc = 0, pon_soc = 0, full_soc = 0, cutoff_soc = 0; + u32 shutdown[SDAM_MAX] = {0}; char ocv_type[20] = "NONE"; if (!chip->profile_loaded) { @@ -2537,6 +2537,24 @@ static int qg_determine_pon_soc(struct qpnp_qg *chip) return 0; } + /* read all OCVs */ + for (i = S7_PON_OCV; i < PON_OCV_MAX; i++) { + rc = qg_read_ocv(chip, &ocv[i].ocv_uv, + &ocv[i].ocv_raw, i); + if (rc < 0) + pr_err("Failed to read %s OCV rc=%d\n", + ocv[i].ocv_type, rc); + else + qg_dbg(chip, QG_DEBUG_PON, "%s OCV=%d\n", + ocv[i].ocv_type, ocv[i].ocv_uv); + } + + rc = qg_get_battery_temp(chip, &batt_temp); + if (rc < 0) { + pr_err("Failed to read BATT_TEMP at PON rc=%d\n", rc); + goto done; + } + rc = get_rtc_time(&rtc_sec); if (rc < 0) { pr_err("Failed to read RTC time rc=%d\n", rc); @@ -2549,47 +2567,50 @@ static int qg_determine_pon_soc(struct qpnp_qg *chip) goto use_pon_ocv; } - qg_dbg(chip, QG_DEBUG_PON, "Shutdown: Valid=%d SOC=%d OCV=%duV time=%dsecs, time_now=%ldsecs\n", + rc = lookup_soc_ocv(&pon_soc, ocv[S7_PON_OCV].ocv_uv, batt_temp, false); + if (rc < 0) { + pr_err("Failed to lookup S7_PON SOC rc=%d\n", rc); + goto done; + } + + qg_dbg(chip, QG_DEBUG_PON, "Shutdown: Valid=%d SOC=%d OCV=%duV time=%dsecs temp=%d, time_now=%ldsecs temp_now=%d S7_soc=%d\n", shutdown[SDAM_VALID], shutdown[SDAM_SOC], shutdown[SDAM_OCV_UV], shutdown[SDAM_TIME_SEC], - rtc_sec); + shutdown[SDAM_TEMP], + rtc_sec, batt_temp, + pon_soc); /* * Use the shutdown SOC if - * 1. The device was powered off for < ignore_shutdown_time - * 2. SDAM read is a success & SDAM data is valid + * 1. SDAM read is a success & SDAM data is valid + * 2. The device was powered off for < ignore_shutdown_time + * 2. Batt temp has not changed more than shutdown_temp_diff */ - if (shutdown[SDAM_VALID] && is_between(0, - chip->dt.ignore_shutdown_soc_secs, - (rtc_sec - shutdown[SDAM_TIME_SEC]))) { - use_pon_ocv = false; - ocv_uv = shutdown[SDAM_OCV_UV]; - soc = shutdown[SDAM_SOC]; - strlcpy(ocv_type, "SHUTDOWN_SOC", 20); - qg_dbg(chip, QG_DEBUG_PON, "Using SHUTDOWN_SOC @ PON\n"); - } + if (!shutdown[SDAM_VALID]) + goto use_pon_ocv; -use_pon_ocv: - if (use_pon_ocv == true) { - rc = qg_get_battery_temp(chip, &batt_temp); - if (rc < 0) { - pr_err("Failed to read BATT_TEMP at PON rc=%d\n", rc); - goto done; - } + if (!is_between(0, chip->dt.ignore_shutdown_soc_secs, + (rtc_sec - shutdown[SDAM_TIME_SEC]))) + goto use_pon_ocv; - /* read all OCVs */ - for (i = S7_PON_OCV; i < PON_OCV_MAX; i++) { - rc = qg_read_ocv(chip, &ocv[i].ocv_uv, - &ocv[i].ocv_raw, i); - if (rc < 0) - pr_err("Failed to read %s OCV rc=%d\n", - ocv[i].ocv_type, rc); - else - qg_dbg(chip, QG_DEBUG_PON, "%s OCV=%d\n", - ocv[i].ocv_type, ocv[i].ocv_uv); - } + if (!is_between(0, chip->dt.shutdown_temp_diff, + abs(shutdown[SDAM_TEMP] - batt_temp))) + goto use_pon_ocv; + + if ((chip->dt.shutdown_soc_threshold != -EINVAL) && + !is_between(0, chip->dt.shutdown_soc_threshold, + abs(pon_soc - shutdown[SDAM_SOC]))) + goto use_pon_ocv; + + use_pon_ocv = false; + ocv_uv = shutdown[SDAM_OCV_UV]; + soc = shutdown[SDAM_SOC]; + strlcpy(ocv_type, "SHUTDOWN_SOC", 20); + qg_dbg(chip, QG_DEBUG_PON, "Using SHUTDOWN_SOC @ PON\n"); +use_pon_ocv: + if (use_pon_ocv == true) { if (ocv[S3_LAST_OCV].ocv_raw == FIFO_V_RESET_VAL) { if (!ocv[SDAM_PON_OCV].ocv_uv) { strlcpy(ocv_type, "S7_PON_SOC", 20); @@ -2619,11 +2640,36 @@ static int qg_determine_pon_soc(struct qpnp_qg *chip) } ocv_uv = CAP(QG_MIN_OCV_UV, QG_MAX_OCV_UV, ocv_uv); - rc = lookup_soc_ocv(&soc, ocv_uv, batt_temp, false); + rc = lookup_soc_ocv(&pon_soc, ocv_uv, batt_temp, false); if (rc < 0) { pr_err("Failed to lookup SOC@PON rc=%d\n", rc); goto done; } + + rc = lookup_soc_ocv(&full_soc, chip->bp.float_volt_uv, + batt_temp, true); + if (rc < 0) { + pr_err("Failed to lookup FULL_SOC@PON rc=%d\n", rc); + goto done; + } + + rc = lookup_soc_ocv(&cutoff_soc, + chip->dt.vbatt_cutoff_mv * 1000, + batt_temp, false); + if (rc < 0) { + pr_err("Failed to lookup CUTOFF_SOC@PON rc=%d\n", rc); + goto done; + } + + if ((full_soc - cutoff_soc) > 0 && (pon_soc - cutoff_soc) > 0) + soc = DIV_ROUND_UP(((pon_soc - cutoff_soc) * 100), + (full_soc - cutoff_soc)); + else + soc = pon_soc; + + qg_dbg(chip, QG_DEBUG_PON, "v_float=%d v_cutoff=%d FULL_SOC=%d CUTOFF_SOC=%d PON_SYS_SOC=%d pon_soc=%d\n", + chip->bp.float_volt_uv, chip->dt.vbatt_cutoff_mv * 1000, + full_soc, cutoff_soc, pon_soc, soc); } done: if (rc < 0) { @@ -3087,6 +3133,7 @@ static int qg_alg_init(struct qpnp_qg *chip) #define DEFAULT_CL_MAX_DEC_DECIPERC 20 #define DEFAULT_CL_MIN_LIM_DECIPERC 500 #define DEFAULT_CL_MAX_LIM_DECIPERC 100 +#define DEFAULT_SHUTDOWN_TEMP_DIFF 60 /* 6 degC */ #define DEFAULT_ESR_QUAL_CURRENT_UA 130000 #define DEFAULT_ESR_QUAL_VBAT_UV 7000 #define DEFAULT_ESR_DISABLE_SOC 1000 @@ -3272,6 +3319,12 @@ static int qg_parse_dt(struct qpnp_qg *chip) else chip->dt.ignore_shutdown_soc_secs = temp; + rc = of_property_read_u32(node, "qcom,shutdown-temp-diff", &temp); + if (rc < 0) + chip->dt.shutdown_temp_diff = DEFAULT_SHUTDOWN_TEMP_DIFF; + else + chip->dt.shutdown_temp_diff = temp; + chip->dt.hold_soc_while_full = of_property_read_bool(node, "qcom,hold-soc-while-full"); @@ -3315,6 +3368,12 @@ static int qg_parse_dt(struct qpnp_qg *chip) else chip->dt.esr_min_ibat_ua = (int)temp; + rc = of_property_read_u32(node, "qcom,shutdown_soc_threshold", &temp); + if (rc < 0) + chip->dt.shutdown_soc_threshold = -EINVAL; + else + chip->dt.shutdown_soc_threshold = temp; + chip->dt.qg_ext_sense = of_property_read_bool(node, "qcom,qg-ext-sns"); /* Capacity learning params*/ diff --git a/drivers/power/supply/qcom/qpnp-qnovo5.c b/drivers/power/supply/qcom/qpnp-qnovo5.c index 5037fa25e42c29933199b33399a50726138dc041..5165d976fee7bbeeaa5df9d915c64ecc366345ae 100644 --- a/drivers/power/supply/qcom/qpnp-qnovo5.c +++ b/drivers/power/supply/qcom/qpnp-qnovo5.c @@ -227,6 +227,19 @@ static int pt_dis_votable_cb(struct votable *votable, void *data, int disable, { struct qnovo *chip = data; int rc; + u8 val = 0; + + if (!disable) { + rc = qnovo5_write(chip, QNOVO_PHASE, &val, 1); + if (rc < 0) + dev_err(chip->dev, "Couldn't write to QNOVO_PHASE rc=%d\n", + rc); + + rc = qnovo5_write(chip, QNOVO_P2_TICK, &val, 1); + if (rc < 0) + dev_err(chip->dev, "Couldn't write to QNOVO_P2_TICK rc=%d\n", + rc); + } rc = qnovo5_masked_write(chip, QNOVO_PE_CTRL, QNOVO_PTRAIN_EN_BIT, (bool)disable ? 0 : QNOVO_PTRAIN_EN_BIT); @@ -305,6 +318,7 @@ enum { PE_CTRL_REG, PTRAIN_STS_REG, ERR_STS_REG, + ERROR_MASK_REG, PREST1, NREST1, NPULS1, @@ -371,6 +385,12 @@ static struct param_info params[] = { .num_regs = 1, .units_str = "", }, + [ERROR_MASK_REG] = { + .name = "ERROR_MASK", + .start_addr = QNOVO_ERROR_MASK, + .num_regs = 1, + .units_str = "", + }, [PREST1] = { .name = "PREST1", .start_addr = QNOVO_PREST1_CTRL, @@ -443,7 +463,7 @@ static struct param_info params[] = { .name = "PCURR1", .start_addr = QNOVO_PCURR1_LSB, .num_regs = 2, - .reg_to_unit_multiplier = 305185, /* converts to nA */ + .reg_to_unit_multiplier = 488281, /* converts to nA */ .reg_to_unit_divider = 1, .units_str = "uA", }, @@ -451,7 +471,7 @@ static struct param_info params[] = { .name = "PCURR1_SUM", .start_addr = QNOVO_PCURR1_SUM_LSB, .num_regs = 2, - .reg_to_unit_multiplier = 305185, /* converts to nA */ + .reg_to_unit_multiplier = 488281, /* converts to nA */ .reg_to_unit_divider = 1, .units_str = "uA", }, @@ -459,8 +479,10 @@ static struct param_info params[] = { .name = "PCURR1_TERMINAL", .start_addr = QNOVO_PCURR1_TERMINAL_LSB, .num_regs = 2, - .reg_to_unit_multiplier = 305185, /* converts to nA */ + .reg_to_unit_multiplier = 488281, /* converts to nA */ .reg_to_unit_divider = 1, + .min_val = -10000000, + .max_val = 10000000, .units_str = "uA", }, [PTTIME] = { @@ -477,6 +499,8 @@ static struct param_info params[] = { .num_regs = 2, .reg_to_unit_multiplier = 1, .reg_to_unit_divider = 1, + .min_val = 0, + .max_val = 65535, .units_str = "S", }, [NREST2] = { @@ -529,7 +553,7 @@ static struct param_info params[] = { .name = "PCURR2", .start_addr = QNOVO_PCURR2_LSB, .num_regs = 2, - .reg_to_unit_multiplier = 305185, /* converts to nA */ + .reg_to_unit_multiplier = 488281, /* converts to nA */ .reg_to_unit_divider = 1, .units_str = "uA", }, @@ -875,7 +899,7 @@ static ssize_t current_store(struct class *c, struct class_attribute *attr, if (i < 0) return -EINVAL; - if (kstrtoul(ubuf, 0, &val_uA)) + if (kstrtol(ubuf, 0, &val_uA)) return -EINVAL; if (val_uA < params[i].min_val || val_uA > params[i].max_val) { @@ -998,6 +1022,7 @@ CLASS_ATTR_IDX_RW(fcc_uA_request, val); CLASS_ATTR_IDX_RW(PE_CTRL_REG, reg); CLASS_ATTR_IDX_RO(PTRAIN_STS_REG, reg); CLASS_ATTR_IDX_RO(ERR_STS_REG, reg); +CLASS_ATTR_IDX_RW(ERROR_MASK, reg); CLASS_ATTR_IDX_RW(PREST1_uS, time); CLASS_ATTR_IDX_RW(NREST1_uS, time); CLASS_ATTR_IDX_RW(NPULS1_uS, time); @@ -1035,6 +1060,7 @@ static struct attribute *qnovo_class_attrs[] = { [PE_CTRL_REG] = &class_attr_PE_CTRL_REG.attr, [PTRAIN_STS_REG] = &class_attr_PTRAIN_STS_REG.attr, [ERR_STS_REG] = &class_attr_ERR_STS_REG.attr, + [ERROR_MASK_REG] = &class_attr_ERROR_MASK.attr, [PREST1] = &class_attr_PREST1_uS.attr, [NREST1] = &class_attr_NREST1_uS.attr, [NPULS1] = &class_attr_NPULS1_uS.attr, diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index b498c5d3d2354daa400ba115e3c87a7593aefa3f..d7063d7b03a8181d4f76af37cf60342a09358d09 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -220,6 +220,7 @@ module_param_named( ); #define PMI632_MAX_ICL_UA 3000000 +#define PM6150_MAX_FCC_UA 3000000 static int smb5_chg_config_init(struct smb5 *chip) { struct smb_charger *chg = &chip->chg; @@ -256,6 +257,7 @@ static int smb5_chg_config_init(struct smb5 *chip) chg->param = smb5_pm8150b_params; chg->name = "pm6150_charger"; chg->wa_flags |= SW_THERM_REGULATION_WA; + chg->main_fcc_max = PM6150_MAX_FCC_UA; break; case PMI632_SUBTYPE: chip->chg.smb_version = PMI632_SUBTYPE; @@ -291,6 +293,7 @@ static int smb5_chg_config_init(struct smb5 *chip) #define MICRO_1P5A 1500000 #define MICRO_P1A 100000 #define MICRO_1PA 1000000 +#define MICRO_3PA 3000000 #define OTG_DEFAULT_DEGLITCH_TIME_MS 50 #define DEFAULT_WD_BARK_TIME 64 static int smb5_parse_dt(struct smb5 *chip) @@ -347,7 +350,7 @@ static int smb5_parse_dt(struct smb5 *chip) "qcom,otg-cl-ua", &chg->otg_cl_ua); if (rc < 0) chg->otg_cl_ua = (chip->chg.smb_version == PMI632_SUBTYPE) ? - MICRO_1PA : MICRO_1P5A; + MICRO_1PA : MICRO_3PA; rc = of_property_read_u32(node, "qcom,chg-term-src", &chip->dt.term_current_src); @@ -399,7 +402,7 @@ static int smb5_parse_dt(struct smb5 *chip) chip->dt.hvdcp_disable = of_property_read_bool(node, "qcom,hvdcp-disable"); - + chg->hvdcp_disable = chip->dt.hvdcp_disable; rc = of_property_read_u32(node, "qcom,chg-inhibit-threshold-mv", &chip->dt.chg_inhibit_thr_mv); @@ -441,11 +444,22 @@ static int smb5_parse_dt(struct smb5 *chip) "qcom,fcc-stepping-enable"); /* Extract ADC channels */ - rc = smblib_get_iio_channel(chg, "usb_in_voltage", - &chg->iio.usbin_v_chan); + rc = smblib_get_iio_channel(chg, "mid_voltage", &chg->iio.mid_chan); if (rc < 0) return rc; + if (!chg->iio.mid_chan) { + rc = smblib_get_iio_channel(chg, "usb_in_voltage", + &chg->iio.usbin_v_chan); + if (rc < 0) + return rc; + + if (!chg->iio.usbin_v_chan) { + dev_err(chg->dev, "No voltage channel defined"); + return -EINVAL; + } + } + rc = smblib_get_iio_channel(chg, "chg_temp", &chg->iio.temp_chan); if (rc < 0) return rc; @@ -885,6 +899,7 @@ static enum power_supply_property smb5_usb_main_props[] = { POWER_SUPPLY_PROP_FLASH_ACTIVE, POWER_SUPPLY_PROP_FLASH_TRIGGER, POWER_SUPPLY_PROP_TOGGLE_STAT, + POWER_SUPPLY_PROP_MAIN_FCC_MAX, }; static int smb5_usb_main_get_prop(struct power_supply *psy, @@ -927,6 +942,9 @@ static int smb5_usb_main_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_TOGGLE_STAT: val->intval = 0; break; + case POWER_SUPPLY_PROP_MAIN_FCC_MAX: + val->intval = chg->main_fcc_max; + break; default: pr_debug("get prop %d is not supported in usb-main\n", psp); rc = -EINVAL; @@ -964,6 +982,10 @@ static int smb5_usb_main_set_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_TOGGLE_STAT: rc = smblib_toggle_smb_en(chg, val->intval); break; + case POWER_SUPPLY_PROP_MAIN_FCC_MAX: + chg->main_fcc_max = val->intval; + rerun_election(chg->fcc_votable); + break; default: pr_err("set prop %d is not supported\n", psp); rc = -EINVAL; @@ -980,6 +1002,7 @@ static int smb5_usb_main_prop_is_writeable(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_TOGGLE_STAT: + case POWER_SUPPLY_PROP_MAIN_FCC_MAX: rc = 1; break; default: @@ -1156,7 +1179,9 @@ static enum power_supply_property smb5_batt_props[] = { POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED, POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_VOLTAGE_MAX, + POWER_SUPPLY_PROP_VOLTAGE_QNOVO, POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CURRENT_QNOVO, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, POWER_SUPPLY_PROP_TEMP, @@ -1234,10 +1259,18 @@ static int smb5_batt_get_prop(struct power_supply *psy, val->intval = get_client_vote(chg->fv_votable, BATT_PROFILE_VOTER); break; + case POWER_SUPPLY_PROP_VOLTAGE_QNOVO: + val->intval = get_client_vote_locked(chg->fv_votable, + QNOVO_VOTER); + break; case POWER_SUPPLY_PROP_CURRENT_NOW: rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_CURRENT_NOW, val); break; + case POWER_SUPPLY_PROP_CURRENT_QNOVO: + val->intval = get_client_vote_locked(chg->fcc_votable, + QNOVO_VOTER); + break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: val->intval = get_client_vote(chg->fcc_votable, BATT_PROFILE_VOTER); @@ -1338,6 +1371,10 @@ static int smb5_batt_set_prop(struct power_supply *psy, chg->batt_profile_fv_uv = val->intval; vote(chg->fv_votable, BATT_PROFILE_VOTER, true, val->intval); break; + case POWER_SUPPLY_PROP_VOLTAGE_QNOVO: + vote(chg->fv_votable, QNOVO_VOTER, (val->intval >= 0), + val->intval); + break; case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED: chg->step_chg_enabled = !!val->intval; break; @@ -1352,6 +1389,18 @@ static int smb5_batt_set_prop(struct power_supply *psy, chg->batt_profile_fcc_ua = val->intval; vote(chg->fcc_votable, BATT_PROFILE_VOTER, true, val->intval); break; + case POWER_SUPPLY_PROP_CURRENT_QNOVO: + vote(chg->pl_disable_votable, PL_QNOVO_VOTER, + val->intval != -EINVAL && val->intval < 2000000, 0); + if (val->intval == -EINVAL) { + vote(chg->fcc_votable, BATT_PROFILE_VOTER, + true, chg->batt_profile_fcc_ua); + vote(chg->fcc_votable, QNOVO_VOTER, false, 0); + } else { + vote(chg->fcc_votable, QNOVO_VOTER, true, val->intval); + vote(chg->fcc_votable, BATT_PROFILE_VOTER, false, 0); + } + break; case POWER_SUPPLY_PROP_SET_SHIP_MODE: /* Not in ship mode as long as the device is active */ if (!val->intval) @@ -1611,16 +1660,6 @@ static int smb5_configure_micro_usb(struct smb_charger *chg) return rc; } - /* Enable HVDCP and BC 1.2 source detection */ - rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, - HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT, - HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT); - if (rc < 0) { - dev_err(chg->dev, - "Couldn't enable HVDCP detection rc=%d\n", rc); - return rc; - } - return rc; } @@ -1751,10 +1790,16 @@ static int smb5_init_hw(struct smb5 *chip) } } - /* Use SW based VBUS control, disable HW autonomous mode */ + /* + * Disable HVDCP autonomous mode operation by default. Additionally, if + * specified in DT: disable HVDCP and HVDCP authentication algorithm. + */ + val = (chg->hvdcp_disable) ? 0 : + (HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_EN_BIT); rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, - HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT, - HVDCP_AUTH_ALG_EN_CFG_BIT); + (HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_EN_BIT | + HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT), + val); if (rc < 0) { dev_err(chg->dev, "Couldn't configure HVDCP rc=%d\n", rc); return rc; @@ -2066,15 +2111,6 @@ static int smb5_init_hw(struct smb5 *chip) } } - /* set the Source (OTG) mode current limit */ - rc = smblib_masked_write(chg, DCDC_OTG_CURRENT_LIMIT_CFG_REG, - OTG_CURRENT_LIMIT_MASK, OTG_CURRENT_LIMIT_3000_MA); - if (rc < 0) { - dev_err(chg->dev, "Couldn't configure DCDC_OTG_CURRENT_LIMIT_CFG rc=%d\n", - rc); - return rc; - } - if (chg->sw_jeita_enabled) { rc = smblib_disable_hw_jeita(chg, true); if (rc < 0) { @@ -2484,6 +2520,13 @@ static int smb5_request_interrupts(struct smb5 *chip) if (chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq) chg->usb_icl_change_irq_enabled = true; + /* + * Disable WDOG SNARL IRQ by default to prevent IRQ storm. If required + * for any application, enable it through votable. + */ + if (chg->irq_info[WDOG_SNARL_IRQ].irq) + vote(chg->wdog_snarl_irq_en_votable, DEFAULT_VOTER, false, 0); + return rc; } @@ -2642,6 +2685,7 @@ static int smb5_probe(struct platform_device *pdev) chg->die_health = -EINVAL; chg->connector_health = -EINVAL; chg->otg_present = false; + chg->main_fcc_max = -EINVAL; chg->regmap = dev_get_regmap(chg->dev->parent, NULL); if (!chg->regmap) { diff --git a/drivers/power/supply/qcom/smb1355-charger.c b/drivers/power/supply/qcom/smb1355-charger.c index 39a8ea5b8f3cc00faa00cacebd2a3a9086fecf70..3bf814e4dc29baf9274bde151ef63ee501b74f28 100644 --- a/drivers/power/supply/qcom/smb1355-charger.c +++ b/drivers/power/supply/qcom/smb1355-charger.c @@ -522,6 +522,7 @@ static int smb1355_parse_dt(struct smb1355 *chip) static enum power_supply_property smb1355_parallel_props[] = { POWER_SUPPLY_PROP_CHARGE_TYPE, + POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_CHARGING_ENABLED, POWER_SUPPLY_PROP_PIN_ENABLED, POWER_SUPPLY_PROP_INPUT_SUSPEND, @@ -605,6 +606,7 @@ static int smb1355_parallel_get_prop(struct power_supply *psy, rc = smb1355_get_prop_batt_charge_type(chip, val); break; case POWER_SUPPLY_PROP_CHARGING_ENABLED: + case POWER_SUPPLY_PROP_ONLINE: rc = smb1355_read(chip, BATTERY_STATUS_3_REG, &stat); if (rc >= 0) val->intval = (bool)(stat & ENABLE_CHARGING_BIT); @@ -1362,7 +1364,7 @@ static int smb1355_probe(struct platform_device *pdev) chip->c_charger_temp_max = -EINVAL; mutex_init(&chip->write_lock); INIT_DELAYED_WORK(&chip->die_temp_work, die_temp_work); - chip->disabled = true; + chip->disabled = false; chip->die_temp_deciDegC = -EINVAL; chip->regmap = dev_get_regmap(chip->dev->parent, NULL); diff --git a/drivers/power/supply/qcom/smb1390-charger.c b/drivers/power/supply/qcom/smb1390-charger.c index 3e59a24c47e2654f84aa21f2b21f21d9ab0ffe36..128a2877e415f9ba84caf7c1803a4d6b8d444d9b 100644 --- a/drivers/power/supply/qcom/smb1390-charger.c +++ b/drivers/power/supply/qcom/smb1390-charger.c @@ -690,6 +690,11 @@ static void smb1390_release_channels(struct smb1390 *chip) static int smb1390_create_votables(struct smb1390 *chip) { + chip->cp_awake_votable = create_votable("CP_AWAKE", VOTE_SET_ANY, + smb1390_awake_vote_cb, chip); + if (IS_ERR(chip->cp_awake_votable)) + return PTR_ERR(chip->cp_awake_votable); + chip->disable_votable = create_votable("CP_DISABLE", VOTE_SET_ANY, smb1390_disable_vote_cb, chip); if (IS_ERR(chip->disable_votable)) @@ -700,11 +705,6 @@ static int smb1390_create_votables(struct smb1390 *chip) if (IS_ERR(chip->ilim_votable)) return PTR_ERR(chip->ilim_votable); - chip->cp_awake_votable = create_votable("CP_AWAKE", VOTE_SET_ANY, - smb1390_awake_vote_cb, chip); - if (IS_ERR(chip->cp_awake_votable)) - return PTR_ERR(chip->cp_awake_votable); - return 0; } @@ -712,6 +712,7 @@ static void smb1390_destroy_votables(struct smb1390 *chip) { destroy_votable(chip->disable_votable); destroy_votable(chip->ilim_votable); + destroy_votable(chip->cp_awake_votable); } static int smb1390_init_hw(struct smb1390 *chip) diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index a372c21e1a282166c9693aeee9556fddf7acc802..265e3845cfb8fa5da26642b48aaf2c9106f4cb87 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -176,13 +176,15 @@ int smblib_icl_override(struct smb_charger *chg, bool override) return rc; } -static int smblib_select_sec_charger(struct smb_charger *chg, int sec_chg) +/* + * This function does smb_en pin access, which is lock protected. + * It should be called with smb_lock held. + */ +static int smblib_select_sec_charger_locked(struct smb_charger *chg, + int sec_chg) { int rc; - if (sec_chg == chg->sec_chg_selected) - return 0; - switch (sec_chg) { case POWER_SUPPLY_CHARGER_SEC_CP: vote(chg->pl_disable_votable, PL_SMB_EN_VOTER, true, 0); @@ -238,7 +240,44 @@ static int smblib_select_sec_charger(struct smb_charger *chg, int sec_chg) break; } + return rc; +} + +static int smblib_select_sec_charger(struct smb_charger *chg, int sec_chg, + int reason, bool toggle) +{ + int rc; + + mutex_lock(&chg->smb_lock); + + if (toggle && sec_chg == POWER_SUPPLY_CHARGER_SEC_CP) { + rc = smblib_select_sec_charger_locked(chg, + POWER_SUPPLY_CHARGER_SEC_NONE); + if (rc < 0) { + dev_err(chg->dev, "Couldn't disable secondary charger rc=%d\n", + rc); + goto unlock_out; + } + + /* + * A minimum of 20us delay is expected before switching on STAT + * pin. + */ + usleep_range(20, 30); + } + + rc = smblib_select_sec_charger_locked(chg, sec_chg); + if (rc < 0) { + dev_err(chg->dev, "Couldn't switch secondary charger rc=%d\n", + rc); + goto unlock_out; + } + chg->sec_chg_selected = sec_chg; + chg->cp_reason = reason; + +unlock_out: + mutex_unlock(&chg->smb_lock); return rc; } @@ -492,6 +531,34 @@ static const struct apsd_result *smblib_get_apsd_result(struct smb_charger *chg) return result; } +#define INPUT_NOT_PRESENT 0 +#define INPUT_PRESENT_USB BIT(1) +#define INPUT_PRESENT_DC BIT(2) +static int smblib_is_input_present(struct smb_charger *chg, + int *present) +{ + int rc; + union power_supply_propval pval = {0, }; + + *present = INPUT_NOT_PRESENT; + + rc = smblib_get_prop_usb_present(chg, &pval); + if (rc < 0) { + pr_err("Couldn't get usb presence status rc=%d\n", rc); + return rc; + } + *present |= pval.intval ? INPUT_PRESENT_USB : INPUT_NOT_PRESENT; + + rc = smblib_get_prop_dc_present(chg, &pval); + if (rc < 0) { + pr_err("Couldn't get dc presence status rc=%d\n", rc); + return rc; + } + *present |= pval.intval ? INPUT_PRESENT_DC : INPUT_NOT_PRESENT; + + return 0; +} + /******************** * REGISTER SETTERS * ********************/ @@ -734,13 +801,17 @@ int smblib_get_prop_from_bms(struct smb_charger *chg, int smblib_configure_hvdcp_apsd(struct smb_charger *chg, bool enable) { int rc; - u8 mask = HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT; + u8 mask = (BC1P2_SRC_DETECT_BIT | HVDCP_EN_BIT | + HVDCP_AUTH_ALG_EN_CFG_BIT); + + u8 val = BC1P2_SRC_DETECT_BIT | (chg->hvdcp_disable ? 0 : + (HVDCP_EN_BIT | HVDCP_AUTH_ALG_EN_CFG_BIT)); if (chg->pd_not_supported) return 0; rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, mask, - enable ? mask : 0); + enable ? val : 0); if (rc < 0) smblib_err(chg, "failed to write USBIN_OPTIONS_1_CFG rc=%d\n", rc); @@ -902,16 +973,12 @@ static void smblib_uusb_removal(struct smb_charger *chg) int rc; struct smb_irq_data *data; struct storm_watch *wdata; + int sec_charger; - mutex_lock(&chg->smb_lock); - chg->cp_reason = POWER_SUPPLY_CP_NONE; - rc = smblib_select_sec_charger(chg, - chg->sec_pl_present ? POWER_SUPPLY_CHARGER_SEC_PL : - POWER_SUPPLY_CHARGER_SEC_NONE); - if (rc < 0) - dev_err(chg->dev, "Couldn't disable secondary charger rc=%d\n", - rc); - mutex_lock(&chg->smb_lock); + sec_charger = chg->sec_pl_present ? POWER_SUPPLY_CHARGER_SEC_PL : + POWER_SUPPLY_CHARGER_SEC_NONE; + smblib_select_sec_charger(chg, sec_charger, POWER_SUPPLY_CP_NONE, + false); cancel_delayed_work_sync(&chg->pl_enable_work); @@ -972,6 +1039,28 @@ static void smblib_uusb_removal(struct smb_charger *chg) if (rc < 0) smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n", rc); + + /* + * if non-compliant charger caused UV, restore original max pulses + * and turn SUSPEND_ON_COLLAPSE_USBIN_BIT back on. + */ + if (chg->qc2_unsupported_voltage) { + rc = smblib_masked_write(chg, HVDCP_PULSE_COUNT_MAX_REG, + HVDCP_PULSE_COUNT_MAX_QC2_MASK, + chg->qc2_max_pulses); + if (rc < 0) + smblib_err(chg, "Couldn't restore max pulses rc=%d\n", + rc); + + rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG, + SUSPEND_ON_COLLAPSE_USBIN_BIT, + SUSPEND_ON_COLLAPSE_USBIN_BIT); + if (rc < 0) + smblib_err(chg, "Couldn't turn on SUSPEND_ON_COLLAPSE_USBIN_BIT rc=%d\n", + rc); + + chg->qc2_unsupported_voltage = QC2_COMPLIANT; + } } void smblib_suspend_on_debug_battery(struct smb_charger *chg) @@ -1056,7 +1145,6 @@ static int set_sdp_current(struct smb_charger *chg, int icl_ua) icl_options = CFG_USB3P0_SEL_BIT | USB51_MODE_BIT; break; default: - smblib_err(chg, "ICL %duA isn't supported for SDP\n", icl_ua); return -EINVAL; } @@ -1142,7 +1230,17 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua) goto out; } } else { - set_sdp_current(chg, 100000); + /* + * Try USB 2.0/3,0 option first on USB path when maximum input + * current limit is 500mA or below for better accuracy; in case + * of error, proceed to use USB high-current mode. + */ + if (icl_ua <= USBIN_500MA) { + rc = set_sdp_current(chg, icl_ua); + if (rc >= 0) + goto out; + } + rc = smblib_set_charge_param(chg, &chg->param.usb_icl, icl_ua); if (rc < 0) { smblib_err(chg, "Couldn't set HC ICL rc=%d\n", rc); @@ -1229,36 +1327,8 @@ int smblib_toggle_smb_en(struct smb_charger *chg, int toggle) if (!toggle) return rc; - mutex_lock(&chg->smb_lock); - - if (chg->sec_chg_selected == POWER_SUPPLY_CHARGER_SEC_CP) { - /* Pull down SMB_EN pin */ - rc = smblib_select_sec_charger(chg, - POWER_SUPPLY_CHARGER_SEC_NONE); - if (rc < 0) { - dev_err(chg->dev, "Couldn't disable SMB_EN pin rc=%d\n", - rc); - goto out; - } - - /* - * A minimum of 20us delay is expected before switching on STAT - * pin. - */ - usleep_range(20, 30); - - /* Pull up SMB_EN pin and enable Charge Pump under HW control */ - rc = smblib_select_sec_charger(chg, - POWER_SUPPLY_CHARGER_SEC_CP); - if (rc < 0) { - dev_err(chg->dev, "Couldn't enable CP rc=%d\n", - rc); - goto out; - } - } - -out: - mutex_unlock(&chg->smb_lock); + rc = smblib_select_sec_charger(chg, chg->sec_chg_selected, + chg->cp_reason, true); return rc; } @@ -1342,10 +1412,13 @@ static int smblib_wdog_snarl_irq_en_vote_callback(struct votable *votable, if (!chg->irq_info[WDOG_SNARL_IRQ].irq) return 0; - if (enable) + if (enable) { enable_irq(chg->irq_info[WDOG_SNARL_IRQ].irq); - else + enable_irq_wake(chg->irq_info[WDOG_SNARL_IRQ].irq); + } else { + disable_irq_wake(chg->irq_info[WDOG_SNARL_IRQ].irq); disable_irq_nosync(chg->irq_info[WDOG_SNARL_IRQ].irq); + } return 0; } @@ -2619,44 +2692,120 @@ int smblib_get_prop_usb_voltage_max(struct smb_charger *chg, return 0; } -int smblib_get_prop_usb_voltage_now(struct smb_charger *chg, - union power_supply_propval *val) +static int smblib_estimate_hvdcp_voltage(struct smb_charger *chg, + union power_supply_propval *val) { - int rc, ret = 0; + int rc; + u8 stat; - /* set 12V OV to 14.6V */ - if (chg->smb_version == PM8150B_SUBTYPE) { - rc = smblib_masked_write(chg, USB_ENG_SSUPPLY_USB2_REG, - ENG_SSUPPLY_12V_OV_OPT_BIT, - ENG_SSUPPLY_12V_OV_OPT_BIT); - if (rc < 0) { - smblib_err(chg, "Couldn't set USB_ENG_SSUPPLY_USB2_REG rc=%d\n", - rc); - return -ENODATA; - } + rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read QC_CHANGE_STATUS_REG rc=%d\n", + rc); + return rc; } - if (chg->iio.usbin_v_chan) { - rc = iio_read_channel_processed(chg->iio.usbin_v_chan, - &val->intval); - if (rc < 0) - ret = -ENODATA; - } else { - ret = -ENODATA; + if (stat & QC_5V_BIT) + val->intval = MICRO_5V; + else if (stat & QC_9V_BIT) + val->intval = MICRO_9V; + else if (stat & QC_12V_BIT) + val->intval = MICRO_12V; + + return 0; +} + +#define HVDCP3_STEP_UV 200000 +static int smblib_estimate_adaptor_voltage(struct smb_charger *chg, + union power_supply_propval *val) +{ + switch (chg->real_charger_type) { + case POWER_SUPPLY_TYPE_USB_HVDCP: + return smblib_estimate_hvdcp_voltage(chg, val); + case POWER_SUPPLY_TYPE_USB_HVDCP_3: + val->intval = MICRO_5V + (HVDCP3_STEP_UV * chg->pulse_cnt); + break; + case POWER_SUPPLY_TYPE_USB_PD: + /* Take the average of min and max values */ + val->intval = chg->voltage_min_uv + + ((chg->voltage_max_uv - chg->voltage_min_uv) / 2); + break; + default: + val->intval = MICRO_5V; + break; } - /* restore 12V OV to 13.2V */ - if (chg->smb_version == PM8150B_SUBTYPE) { - rc = smblib_masked_write(chg, USB_ENG_SSUPPLY_USB2_REG, - ENG_SSUPPLY_12V_OV_OPT_BIT, 0); - if (rc < 0) { - smblib_err(chg, "Couldn't restore USB_ENG_SSUPPLY_USB2_REG rc=%d\n", - rc); - ret = -ENODATA; - } + return 0; +} + +static int smblib_read_mid_voltage_chan(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc; + + if (!chg->iio.mid_chan) + return -ENODATA; + + rc = iio_read_channel_processed(chg->iio.mid_chan, &val->intval); + if (rc < 0) { + smblib_err(chg, "Couldn't read MID channel rc=%d\n", rc); + return rc; } - return ret; + /* + * If MID voltage < 1V, it is unreliable. + * Figure out voltage from registers and calculations. + */ + if (val->intval < 1000000) + return smblib_estimate_adaptor_voltage(chg, val); + + return 0; +} + +static int smblib_read_usbin_voltage_chan(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc; + + if (!chg->iio.usbin_v_chan) + return -ENODATA; + + rc = iio_read_channel_processed(chg->iio.usbin_v_chan, &val->intval); + if (rc < 0) { + smblib_err(chg, "Couldn't read USBIN channel rc=%d\n", rc); + return rc; + } + + return 0; +} + +int smblib_get_prop_usb_voltage_now(struct smb_charger *chg, + union power_supply_propval *val) +{ + union power_supply_propval pval = {0, }; + int rc; + + rc = smblib_get_prop_usb_present(chg, &pval); + if (rc < 0) { + smblib_err(chg, "Couldn't get usb presence status rc=%d\n", rc); + return -ENODATA; + } + + /* usb not present */ + if (!pval.intval) { + val->intval = 0; + return 0; + } + + /* + * For PM8150B, use MID_CHG ADC channel because overvoltage is observed + * to occur randomly in the USBIN channel, particularly at high + * voltages. + */ + if (chg->smb_version == PM8150B_SUBTYPE) + return smblib_read_mid_voltage_chan(chg, val); + else + return smblib_read_usbin_voltage_chan(chg, val); } bool smblib_rsbux_low(struct smb_charger *chg, int r_thr) @@ -2729,25 +2878,14 @@ bool smblib_rsbux_low(struct smb_charger *chg, int r_thr) int smblib_get_prop_charger_temp(struct smb_charger *chg, union power_supply_propval *val) { - union power_supply_propval pval = {0, }; - bool usb_present, dc_present; int temp, rc; + int input_present; - rc = smblib_get_prop_usb_present(chg, &pval); - if (rc < 0) { - pr_err("Couldn't get usb presence status rc=%d\n", rc); - return rc; - } - usb_present = pval.intval; - - rc = smblib_get_prop_dc_present(chg, &pval); - if (rc < 0) { - pr_err("Couldn't get dc presence status rc=%d\n", rc); + rc = smblib_is_input_present(chg, &input_present); + if (rc < 0) return rc; - } - dc_present = pval.intval; - if (!usb_present && !dc_present) + if (input_present == INPUT_NOT_PRESENT) return -ENODATA; if (chg->iio.temp_chan) { @@ -3014,7 +3152,6 @@ int smblib_get_prop_input_current_settled(struct smb_charger *chg, return smblib_get_charge_param(chg, &chg->param.icl_stat, &val->intval); } -#define HVDCP3_STEP_UV 200000 int smblib_get_prop_input_voltage_settled(struct smb_charger *chg, union power_supply_propval *val) { @@ -3059,6 +3196,14 @@ int smblib_get_prop_die_health(struct smb_charger *chg) { int rc; u8 stat; + int input_present; + + rc = smblib_is_input_present(chg, &input_present); + if (rc < 0) + return rc; + + if (input_present == INPUT_NOT_PRESENT) + return POWER_SUPPLY_HEALTH_UNKNOWN; if (chg->wa_flags & SW_THERM_REGULATION_WA) { if (chg->die_temp == -ENODATA) @@ -3413,6 +3558,7 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, const union power_supply_propval *val) { int rc = 0; + int sec_charger; chg->pd_active = val->intval; @@ -3432,33 +3578,29 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, * For PPS, Charge Pump is preferred over parallel charger if * present. */ - mutex_lock(&chg->smb_lock); if (chg->pd_active == POWER_SUPPLY_PD_PPS_ACTIVE && chg->sec_cp_present) { rc = smblib_select_sec_charger(chg, - POWER_SUPPLY_CHARGER_SEC_CP); + POWER_SUPPLY_CHARGER_SEC_CP, + POWER_SUPPLY_CP_PPS, false); if (rc < 0) dev_err(chg->dev, "Couldn't enable secondary charger rc=%d\n", rc); - else - chg->cp_reason = POWER_SUPPLY_CP_PPS; } - mutex_unlock(&chg->smb_lock); } else { vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, SDP_100_MA); vote(chg->usb_icl_votable, PD_VOTER, false, 0); vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0); - mutex_lock(&chg->smb_lock); - chg->cp_reason = POWER_SUPPLY_CP_NONE; - rc = smblib_select_sec_charger(chg, - chg->sec_pl_present ? POWER_SUPPLY_CHARGER_SEC_PL : - POWER_SUPPLY_CHARGER_SEC_NONE); + sec_charger = chg->sec_pl_present ? + POWER_SUPPLY_CHARGER_SEC_PL : + POWER_SUPPLY_CHARGER_SEC_NONE; + rc = smblib_select_sec_charger(chg, sec_charger, + POWER_SUPPLY_CP_NONE, false); if (rc < 0) dev_err(chg->dev, "Couldn't enable secondary charger rc=%d\n", rc); - mutex_unlock(&chg->smb_lock); /* PD hard resets failed, rerun apsd */ if (chg->ok_to_pd) { @@ -4016,15 +4158,11 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg, /* for QC3, switch to CP if present */ if ((apsd_result->bit & QC_3P0_BIT) && chg->sec_cp_present) { - mutex_lock(&chg->smb_lock); - rc = smblib_select_sec_charger(chg, - POWER_SUPPLY_CHARGER_SEC_CP); + rc = smblib_select_sec_charger(chg, POWER_SUPPLY_CHARGER_SEC_CP, + POWER_SUPPLY_CP_HVDCP3, false); if (rc < 0) dev_err(chg->dev, "Couldn't enable secondary chargers rc=%d\n", rc); - else - chg->cp_reason = POWER_SUPPLY_CP_HVDCP3; - mutex_unlock(&chg->smb_lock); } smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n", @@ -4062,8 +4200,10 @@ static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg, static void update_sw_icl_max(struct smb_charger *chg, int pst) { + union power_supply_propval pval; int typec_mode; int rp_ua; + int rc; /* while PD is active it should have complete ICL control */ if (chg->pd_active) @@ -4116,9 +4256,15 @@ static void update_sw_icl_max(struct smb_charger *chg, int pst) SDP_100_MA); break; default: - smblib_err(chg, "Unknown APSD %d; forcing 500mA\n", pst); + rc = smblib_get_prop_usb_present(chg, &pval); + if (rc < 0) { + smblib_err(chg, "Couldn't get usb present rc = %d\n", + rc); + return; + } + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, - SDP_CURRENT_UA); + pval.intval ? SDP_CURRENT_UA : SDP_100_MA); break; } } @@ -4356,16 +4502,16 @@ static void typec_src_removal(struct smb_charger *chg) int rc; struct smb_irq_data *data; struct storm_watch *wdata; + int sec_charger; - mutex_lock(&chg->smb_lock); - chg->cp_reason = POWER_SUPPLY_CP_NONE; - rc = smblib_select_sec_charger(chg, - chg->sec_pl_present ? POWER_SUPPLY_CHARGER_SEC_PL : - POWER_SUPPLY_CHARGER_SEC_NONE); + sec_charger = chg->sec_pl_present ? POWER_SUPPLY_CHARGER_SEC_PL : + POWER_SUPPLY_CHARGER_SEC_NONE; + + rc = smblib_select_sec_charger(chg, sec_charger, POWER_SUPPLY_CP_NONE, + false); if (rc < 0) dev_err(chg->dev, "Couldn't disable secondary charger rc=%d\n", rc); - mutex_unlock(&chg->smb_lock); /* disable apsd */ rc = smblib_configure_hvdcp_apsd(chg, false); @@ -4629,8 +4775,10 @@ irqreturn_t dc_plugin_irq_handler(int irq, void *data) struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; union power_supply_propval pval; + int input_present; bool dcin_present, vbus_present; int rc, wireless_vout = 0; + int sec_charger; rc = iio_read_channel_processed(chg->iio.vph_v_chan, &wireless_vout); @@ -4641,20 +4789,12 @@ irqreturn_t dc_plugin_irq_handler(int irq, void *data) wireless_vout /= 100000; wireless_vout *= 100000; - rc = smblib_get_prop_dc_present(chg, &pval); + rc = smblib_is_input_present(chg, &input_present); if (rc < 0) return IRQ_HANDLED; - dcin_present = pval.intval; - - rc = smblib_get_prop_usb_present(chg, &pval); - if (rc < 0) { - smblib_err(chg, "Couldn't get usb present rc = %d\n", - rc); - return IRQ_HANDLED; - } - - vbus_present = pval.intval; + dcin_present = input_present & INPUT_PRESENT_DC; + vbus_present = input_present & INPUT_PRESENT_USB; if (dcin_present) { if (!vbus_present && chg->sec_cp_present) { @@ -4664,26 +4804,23 @@ irqreturn_t dc_plugin_irq_handler(int irq, void *data) dev_err(chg->dev, "Couldn't set dc voltage to 2*vph rc=%d\n", rc); - mutex_lock(&chg->smb_lock); - chg->cp_reason = POWER_SUPPLY_CP_WIRELESS; rc = smblib_select_sec_charger(chg, - POWER_SUPPLY_CHARGER_SEC_CP); + POWER_SUPPLY_CHARGER_SEC_CP, + POWER_SUPPLY_CP_WIRELESS, false); if (rc < 0) dev_err(chg->dev, "Couldn't enable secondary chargers rc=%d\n", rc); - mutex_unlock(&chg->smb_lock); } } else if (chg->cp_reason == POWER_SUPPLY_CP_WIRELESS) { - mutex_lock(&chg->smb_lock); - chg->cp_reason = POWER_SUPPLY_CP_NONE; - rc = smblib_select_sec_charger(chg, - chg->sec_pl_present ? POWER_SUPPLY_CHARGER_SEC_PL : - POWER_SUPPLY_CHARGER_SEC_NONE); + sec_charger = chg->sec_pl_present ? + POWER_SUPPLY_CHARGER_SEC_PL : + POWER_SUPPLY_CHARGER_SEC_NONE; + rc = smblib_select_sec_charger(chg, sec_charger, + POWER_SUPPLY_CP_NONE, false); if (rc < 0) dev_err(chg->dev, "Couldn't disable secondary charger rc=%d\n", rc); - mutex_unlock(&chg->smb_lock); } power_supply_changed(chg->dc_psy); @@ -4966,9 +5103,8 @@ static void pl_update_work(struct work_struct *work) if (chg->sec_chg_selected == POWER_SUPPLY_CHARGER_SEC_CP) return; - mutex_lock(&chg->smb_lock); - smblib_select_sec_charger(chg, POWER_SUPPLY_CHARGER_SEC_PL); - mutex_unlock(&chg->smb_lock); + smblib_select_sec_charger(chg, POWER_SUPPLY_CHARGER_SEC_PL, + POWER_SUPPLY_CP_NONE, false); } static void clear_hdc_work(struct work_struct *work) @@ -5330,6 +5466,8 @@ static void smblib_destroy_votables(struct smb_charger *chg) destroy_votable(chg->awake_votable); if (chg->chg_disable_votable) destroy_votable(chg->chg_disable_votable); + if (chg->wdog_snarl_irq_en_votable) + destroy_votable(chg->wdog_snarl_irq_en_votable); } static void smblib_iio_deinit(struct smb_charger *chg) @@ -5401,16 +5539,15 @@ int smblib_init(struct smb_charger *chg) if (chg->sec_pl_present) { chg->pl.psy = power_supply_get_by_name("parallel"); if (chg->pl.psy) { - mutex_lock(&chg->smb_lock); if (chg->sec_chg_selected != POWER_SUPPLY_CHARGER_SEC_CP) { rc = smblib_select_sec_charger(chg, - POWER_SUPPLY_CHARGER_SEC_PL); + POWER_SUPPLY_CHARGER_SEC_PL, + POWER_SUPPLY_CP_NONE, false); if (rc < 0) smblib_err(chg, "Couldn't config pl charger rc=%d\n", rc); } - mutex_unlock(&chg->smb_lock); if (chg->smb_temp_max == -EINVAL) { rc = smblib_get_thermal_threshold(chg, diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index e67f80eea77d7d43009cadf45875426a4bdda762..4723edcdff5f38d29a1c03c25ef96cbd1c779baa 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -51,6 +51,7 @@ enum print_reason { #define SW_QC3_VOTER "SW_QC3_VOTER" #define AICL_RERUN_VOTER "AICL_RERUN_VOTER" #define SW_ICL_MAX_VOTER "SW_ICL_MAX_VOTER" +#define PL_QNOVO_VOTER "PL_QNOVO_VOTER" #define QNOVO_VOTER "QNOVO_VOTER" #define BATT_PROFILE_VOTER "BATT_PROFILE_VOTER" #define OTG_DELAY_VOTER "OTG_DELAY_VOTER" @@ -290,6 +291,7 @@ struct smb_iio { struct iio_channel *temp_chan; struct iio_channel *usbin_i_chan; struct iio_channel *usbin_v_chan; + struct iio_channel *mid_chan; struct iio_channel *batt_i_chan; struct iio_channel *connector_temp_chan; struct iio_channel *sbux_chan; @@ -412,6 +414,7 @@ struct smb_charger { u8 float_cfg; bool use_extcon; bool otg_present; + bool hvdcp_disable; int hw_max_icl_ua; int auto_recharge_soc; enum sink_src_mode sink_src_mode; @@ -427,6 +430,7 @@ struct smb_charger { int skin_temp; int connector_temp; int thermal_status; + int main_fcc_max; /* workaround flag */ u32 wa_flags; diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h index aee35076044c146d430b77cf69f979eecf5ee361..6896360dee91ba5d3edeb76722986931ae229bff 100644 --- a/drivers/power/supply/qcom/smb5-reg.h +++ b/drivers/power/supply/qcom/smb5-reg.h @@ -140,15 +140,6 @@ enum { #define DCDC_FSW_SEL_REG (DCDC_BASE + 0x50) #define DCDC_OTG_CURRENT_LIMIT_CFG_REG (DCDC_BASE + 0x52) -#define OTG_CURRENT_LIMIT_MASK GENMASK(2, 0) -enum { - OTG_CURRENT_LIMIT_500_MA, - OTG_CURRENT_LIMIT_1000_MA, - OTG_CURRENT_LIMIT_1500_MA, - OTG_CURRENT_LIMIT_2000_MA, - OTG_CURRENT_LIMIT_2500_MA, - OTG_CURRENT_LIMIT_3000_MA -}; #define DCDC_OTG_CFG_REG (DCDC_BASE + 0x53) #define OTG_EN_SRC_CFG_BIT BIT(1) diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c index d589331d1884b29f938c47f9fb3308ffcb212026..3540d00425d03be01fdcdb77c6f028c975a92617 100644 --- a/drivers/pwm/pwm-meson.c +++ b/drivers/pwm/pwm-meson.c @@ -432,7 +432,6 @@ static int meson_pwm_init_channels(struct meson_pwm *meson, struct meson_pwm_channel *channels) { struct device *dev = meson->chip.dev; - struct device_node *np = dev->of_node; struct clk_init_data init; unsigned int i; char name[255]; @@ -441,7 +440,7 @@ static int meson_pwm_init_channels(struct meson_pwm *meson, for (i = 0; i < meson->chip.npwm; i++) { struct meson_pwm_channel *channel = &channels[i]; - snprintf(name, sizeof(name), "%pOF#mux%u", np, i); + snprintf(name, sizeof(name), "%s#mux%u", dev_name(dev), i); init.name = name; init.ops = &clk_mux_ops; diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index 4c22cb39504094eb32db6ad94e7718eadb38917b..f7b8a86fa5c5e9570a616ccbcdb61e7d427b8ae3 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -33,10 +33,6 @@ #define TBCTL 0x00 #define TBPRD 0x0A -#define TBCTL_RUN_MASK (BIT(15) | BIT(14)) -#define TBCTL_STOP_NEXT 0 -#define TBCTL_STOP_ON_CYCLE BIT(14) -#define TBCTL_FREE_RUN (BIT(15) | BIT(14)) #define TBCTL_PRDLD_MASK BIT(3) #define TBCTL_PRDLD_SHDW 0 #define TBCTL_PRDLD_IMDT BIT(3) @@ -360,7 +356,7 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) /* Channels polarity can be configured from action qualifier module */ configure_polarity(pc, pwm->hwpwm); - /* Enable TBCLK before enabling PWM device */ + /* Enable TBCLK */ ret = clk_enable(pc->tbclk); if (ret) { dev_err(chip->dev, "Failed to enable TBCLK for %s: %d\n", @@ -368,9 +364,6 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) return ret; } - /* Enable time counter for free_run */ - ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_FREE_RUN); - return 0; } @@ -388,6 +381,8 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) aqcsfrc_mask = AQCSFRC_CSFA_MASK; } + /* Update shadow register first before modifying active register */ + ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val); /* * Changes to immediate action on Action Qualifier. This puts * Action Qualifier control on PWM output from next TBCLK @@ -400,9 +395,6 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) /* Disabling TBCLK on PWM disable */ clk_disable(pc->tbclk); - /* Stop Time base counter */ - ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_STOP_NEXT); - /* Disable clock on PWM disable */ pm_runtime_put_sync(chip->dev); } diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index e1ed479d1a01d05385e68350a177146098c22b6e..25f493570262339198dfc65e8493a0ed6ade7c52 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -4499,13 +4499,13 @@ regulator_register(const struct regulator_desc *regulator_desc, !rdev->desc->fixed_uV) rdev->is_switch = true; + dev_set_drvdata(&rdev->dev, rdev); ret = device_register(&rdev->dev); if (ret != 0) { put_device(&rdev->dev); goto unset_supplies; } - dev_set_drvdata(&rdev->dev, rdev); rdev_init_debugfs(rdev); rdev->proxy_consumer = regulator_proxy_consumer_register(dev, config->of_node); diff --git a/drivers/regulator/qpnp-lcdb-regulator.c b/drivers/regulator/qpnp-lcdb-regulator.c index 45c2b7f0e46ffbea75c67d39e236c5bbc53ba143..79be62e302ff5149ae99235877d1f706abed7f45 100644 --- a/drivers/regulator/qpnp-lcdb-regulator.c +++ b/drivers/regulator/qpnp-lcdb-regulator.c @@ -181,6 +181,7 @@ struct ldo_regulator { int soft_start_us; int vreg_ok_dbc_us; int voltage_mv; + int prev_voltage_mv; }; struct ncp_regulator { @@ -195,6 +196,7 @@ struct ncp_regulator { int soft_start_us; int vreg_ok_dbc_us; int voltage_mv; + int prev_voltage_mv; }; struct bst_params { @@ -228,6 +230,7 @@ struct qpnp_lcdb { bool lcdb_enabled; bool settings_saved; bool lcdb_sc_disable; + bool voltage_step_ramp; int sc_count; ktime_t sc_module_enable_time; @@ -249,6 +252,7 @@ enum lcdb_module { LDO, NCP, BST, + LDO_NCP, }; enum pfm_hysteresis { @@ -316,6 +320,12 @@ static u32 ncp_ilim_ma[] = { .valid = _valid \ } \ +static int qpnp_lcdb_set_voltage_step(struct qpnp_lcdb *lcdb, + int voltage_start_mv, u8 type); + +static int qpnp_lcdb_set_voltage(struct qpnp_lcdb *lcdb, + int voltage_mv, u8 type); + static bool is_between(int value, int min, int max) { if (value < min || value > max) @@ -781,9 +791,13 @@ static int qpnp_lcdb_enable_wa(struct qpnp_lcdb *lcdb) return 0; } +#define VOLTAGE_START_MV 4500 +#define VOLTAGE_STEP_MV 500 + static int qpnp_lcdb_enable(struct qpnp_lcdb *lcdb) { int rc = 0, timeout, delay; + int voltage_mv = VOLTAGE_START_MV; u8 val = 0; if (lcdb->lcdb_enabled || lcdb->lcdb_sc_disable) { @@ -806,6 +820,22 @@ static int qpnp_lcdb_enable(struct qpnp_lcdb *lcdb) return rc; } + if (lcdb->voltage_step_ramp) { + if (lcdb->ldo.voltage_mv < VOLTAGE_START_MV) + voltage_mv = lcdb->ldo.voltage_mv; + + rc = qpnp_lcdb_set_voltage(lcdb, voltage_mv, LDO); + if (rc < 0) + return rc; + + if (lcdb->ncp.voltage_mv < VOLTAGE_START_MV) + voltage_mv = lcdb->ncp.voltage_mv; + + rc = qpnp_lcdb_set_voltage(lcdb, voltage_mv, NCP); + if (rc < 0) + return rc; + } + val = MODULE_EN_BIT; rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG, &val, 1); @@ -842,6 +872,17 @@ static int qpnp_lcdb_enable(struct qpnp_lcdb *lcdb) } lcdb->lcdb_enabled = true; + if (lcdb->voltage_step_ramp) { + usleep_range(10000, 11000); + rc = qpnp_lcdb_set_voltage_step(lcdb, + voltage_mv + VOLTAGE_STEP_MV, + LDO_NCP); + if (rc < 0) { + pr_err("Failed to set LCDB voltage rc=%d\n", rc); + return rc; + } + } + pr_debug("lcdb enabled successfully!\n"); return 0; @@ -1128,6 +1169,56 @@ static int qpnp_lcdb_set_voltage(struct qpnp_lcdb *lcdb, return rc; } +static int qpnp_lcdb_set_voltage_step(struct qpnp_lcdb *lcdb, + int voltage_start_mv, u8 type) +{ + int i, ldo_voltage, ncp_voltage, voltage, rc = 0; + + for (i = voltage_start_mv; i <= (MAX_VOLTAGE_MV + VOLTAGE_STEP_MV); + i += VOLTAGE_STEP_MV) { + + ldo_voltage = (lcdb->ldo.voltage_mv < i) ? + lcdb->ldo.voltage_mv : i; + + ncp_voltage = (lcdb->ncp.voltage_mv < i) ? + lcdb->ncp.voltage_mv : i; + if (type == LDO_NCP) { + rc = qpnp_lcdb_set_voltage(lcdb, ldo_voltage, LDO); + if (rc < 0) + return rc; + + rc = qpnp_lcdb_set_voltage(lcdb, ncp_voltage, NCP); + if (rc < 0) + return rc; + + pr_debug(" LDO voltage step %d NCP voltage step %d\n", + ldo_voltage, ncp_voltage); + + if ((i >= lcdb->ncp.voltage_mv) && + (i >= lcdb->ldo.voltage_mv)) + break; + } else { + voltage = (type == LDO) ? ldo_voltage : ncp_voltage; + rc = qpnp_lcdb_set_voltage(lcdb, voltage, type); + if (rc < 0) + return rc; + + pr_debug("%s voltage step %d\n", + (type == LDO) ? "LDO" : "NCP", voltage); + if ((type == LDO) && (i >= lcdb->ldo.voltage_mv)) + break; + + if ((type == NCP) && (i >= lcdb->ncp.voltage_mv)) + break; + + } + + usleep_range(1000, 1100); + } + + return rc; +} + static int qpnp_lcdb_get_voltage(struct qpnp_lcdb *lcdb, u32 *voltage_mv, u8 type) { @@ -1236,11 +1327,17 @@ static int qpnp_lcdb_ldo_regulator_set_voltage(struct regulator_dev *rdev, int rc = 0; struct qpnp_lcdb *lcdb = rdev_get_drvdata(rdev); - rc = qpnp_lcdb_set_voltage(lcdb, min_uV / 1000, LDO); + lcdb->ldo.voltage_mv = min_uV / 1000; + if (lcdb->voltage_step_ramp) + rc = qpnp_lcdb_set_voltage_step(lcdb, + lcdb->ldo.prev_voltage_mv + VOLTAGE_STEP_MV, LDO); + else + rc = qpnp_lcdb_set_voltage(lcdb, lcdb->ldo.voltage_mv, LDO); + if (rc < 0) pr_err("Failed to set LDO voltage rc=%c\n", rc); else - lcdb->ldo.voltage_mv = min_uV / 1000; + lcdb->ldo.prev_voltage_mv = lcdb->ldo.voltage_mv; return rc; } @@ -1309,11 +1406,17 @@ static int qpnp_lcdb_ncp_regulator_set_voltage(struct regulator_dev *rdev, int rc = 0; struct qpnp_lcdb *lcdb = rdev_get_drvdata(rdev); - rc = qpnp_lcdb_set_voltage(lcdb, min_uV / 1000, NCP); + lcdb->ncp.voltage_mv = min_uV / 1000; + if (lcdb->voltage_step_ramp) + rc = qpnp_lcdb_set_voltage_step(lcdb, + lcdb->ncp.prev_voltage_mv + VOLTAGE_STEP_MV, NCP); + else + rc = qpnp_lcdb_set_voltage(lcdb, lcdb->ncp.voltage_mv, NCP); + if (rc < 0) - pr_err("Failed to set LDO voltage rc=%c\n", rc); + pr_err("Failed to set NCP voltage rc=%c\n", rc); else - lcdb->ncp.voltage_mv = min_uV / 1000; + lcdb->ncp.prev_voltage_mv = lcdb->ncp.voltage_mv; return rc; } @@ -1675,6 +1778,8 @@ static int qpnp_lcdb_init_ldo(struct qpnp_lcdb *lcdb) return rc; } + lcdb->ldo.prev_voltage_mv = lcdb->ldo.voltage_mv; + rc = qpnp_lcdb_read(lcdb, lcdb->base + LCDB_LDO_VREG_OK_CTL_REG, &val, 1); if (rc < 0) { @@ -1780,6 +1885,8 @@ static int qpnp_lcdb_init_ncp(struct qpnp_lcdb *lcdb) return rc; } + lcdb->ncp.prev_voltage_mv = lcdb->ncp.voltage_mv; + rc = qpnp_lcdb_read(lcdb, lcdb->base + LCDB_NCP_VREG_OK_CTL_REG, &val, 1); if (rc < 0) { @@ -2038,6 +2145,9 @@ static int qpnp_lcdb_parse_dt(struct qpnp_lcdb *lcdb) if (lcdb->sc_irq < 0) pr_debug("sc irq is not defined\n"); + lcdb->voltage_step_ramp = + of_property_read_bool(node, "qcom,voltage-step-ramp"); + return rc; } diff --git a/drivers/reset/reset-imx7.c b/drivers/reset/reset-imx7.c index 4db177bc89bc4b18bbeb55e8766a7045a7a221a9..fdeac194642946b713a2a3e00fa2ca371b746e4c 100644 --- a/drivers/reset/reset-imx7.c +++ b/drivers/reset/reset-imx7.c @@ -80,7 +80,7 @@ static int imx7_reset_set(struct reset_controller_dev *rcdev, { struct imx7_src *imx7src = to_imx7_src(rcdev); const struct imx7_src_signal *signal = &imx7_src_signals[id]; - unsigned int value = 0; + unsigned int value = assert ? signal->bit : 0; switch (id) { case IMX7_RESET_PCIEPHY: diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 39cc5a69246aad53b82951fedca3a15fefcec213..8052b050624b13749cb2ac7c70ed4fafa10e3026 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "rpmsg_internal.h" #include "qcom_glink_native.h" @@ -289,13 +290,22 @@ static void qcom_glink_channel_release(struct kref *ref) { struct glink_channel *channel = container_of(ref, struct glink_channel, refcount); + struct glink_core_rx_intent *tmp; unsigned long flags; + int iid; CH_INFO(channel, "\n"); wake_up(&channel->intent_req_event); spin_lock_irqsave(&channel->intent_lock, flags); + idr_for_each_entry(&channel->liids, tmp, iid) { + kfree(tmp->data); + kfree(tmp); + } idr_destroy(&channel->liids); + + idr_for_each_entry(&channel->riids, tmp, iid) + kfree(tmp); idr_destroy(&channel->riids); spin_unlock_irqrestore(&channel->intent_lock, flags); @@ -818,9 +828,11 @@ static void qcom_glink_handle_rx_done(struct qcom_glink *glink, static void qcom_glink_handle_intent_req(struct qcom_glink *glink, u32 cid, size_t size) { - struct glink_core_rx_intent *intent; + struct glink_core_rx_intent *intent = NULL; + struct glink_core_rx_intent *tmp; struct glink_channel *channel; unsigned long flags; + int iid; spin_lock_irqsave(&glink->idr_lock, flags); channel = idr_find(&glink->rcids, cid); @@ -831,6 +843,19 @@ static void qcom_glink_handle_intent_req(struct qcom_glink *glink, return; } + spin_lock_irqsave(&channel->intent_lock, flags); + idr_for_each_entry(&channel->liids, tmp, iid) { + if (tmp->size >= size && tmp->reuse) { + intent = tmp; + break; + } + } + spin_unlock_irqrestore(&channel->intent_lock, flags); + if (intent) { + qcom_glink_send_intent_req_ack(glink, channel, !!intent); + return; + } + intent = qcom_glink_alloc_intent(glink, channel, size, false); if (intent) qcom_glink_advertise_intent(glink, channel, intent); @@ -1813,6 +1838,23 @@ static void qcom_glink_set_affinity(struct qcom_glink *glink, u32 *arr, dev_err(glink->dev, "failed to set task affinity\n"); } +static void qcom_glink_notif_reset(void *data) +{ + struct qcom_glink *glink = data; + struct glink_channel *channel; + unsigned long flags; + int cid; + + if (!glink) + return; + atomic_inc(&glink->in_reset); + + spin_lock_irqsave(&glink->idr_lock, flags); + idr_for_each_entry(&glink->lcids, channel, cid) { + wake_up(&channel->intent_req_event); + } + spin_unlock_irqrestore(&glink->idr_lock, flags); +} struct qcom_glink *qcom_glink_native_probe(struct device *dev, unsigned long features, @@ -1871,6 +1913,11 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, return ERR_CAST(glink->task); } + ret = subsys_register_early_notifier(glink->name, XPORT_LAYER_NOTIF, + qcom_glink_notif_reset, glink); + if (ret) + dev_err(dev, "failed to register early notif %d\n", ret); + irq = of_irq_get(dev->of_node, 0); ret = devm_request_irq(dev, irq, qcom_glink_native_intr, @@ -1878,7 +1925,7 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, "glink-native", glink); if (ret) { dev_err(dev, "failed to request IRQ\n"); - return ERR_PTR(ret); + goto unregister; } glink->irq = irq; @@ -1886,8 +1933,10 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, size = of_property_count_u32_elems(dev->of_node, "cpu-affinity"); if (size > 0) { arr = kmalloc_array(size, sizeof(u32), GFP_KERNEL); - if (!arr) - return ERR_PTR(-ENOMEM); + if (!arr) { + ret = -ENOMEM; + goto unregister; + } ret = of_property_read_u32_array(dev->of_node, "cpu-affinity", arr, size); if (!ret) @@ -1898,7 +1947,7 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, ret = qcom_glink_send_version(glink); if (ret) { dev_err(dev, "failed to send version %d\n", ret); - return ERR_PTR(ret); + goto unregister; } ret = qcom_glink_create_chrdev(glink); @@ -1908,6 +1957,10 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, glink->ilc = ipc_log_context_create(GLINK_LOG_PAGE_CNT, glink->name, 0); return glink; + +unregister: + subsys_unregister_early_notifier(glink->name, XPORT_LAYER_NOTIF); + return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(qcom_glink_native_probe); @@ -1925,17 +1978,11 @@ void qcom_glink_native_remove(struct qcom_glink *glink) int ret; unsigned long flags; - atomic_inc(&glink->in_reset); + subsys_unregister_early_notifier(glink->name, XPORT_LAYER_NOTIF); + qcom_glink_notif_reset(glink); disable_irq(glink->irq); cancel_work_sync(&glink->rx_work); - /* Signal all threads to cancel tx */ - spin_lock_irqsave(&glink->idr_lock, flags); - idr_for_each_entry(&glink->lcids, channel, cid) { - wake_up(&channel->intent_req_event); - } - spin_unlock_irqrestore(&glink->idr_lock, flags); - ret = device_for_each_child(glink->dev, NULL, qcom_glink_remove_device); if (ret) dev_warn(glink->dev, "Can't remove GLINK devices: %d\n", ret); diff --git a/drivers/rpmsg/qcom_glink_spi.c b/drivers/rpmsg/qcom_glink_spi.c index ef80542546775691f7ea3950195194c3c6146fc1..b61120658f9109188e08eca7192bfec8369b3263 100644 --- a/drivers/rpmsg/qcom_glink_spi.c +++ b/drivers/rpmsg/qcom_glink_spi.c @@ -77,7 +77,7 @@ do { \ #define SPI_GLINK_CID_MIN 1 #define SPI_GLINK_CID_MAX 65536 -struct glink_msg { +struct glink_spi_msg { __le16 cmd; __le16 param1; __le32 param2; @@ -87,7 +87,7 @@ struct glink_msg { } __packed; /** - * struct glink_defer_cmd - deferred incoming control message + * struct glink_spi_defer_cmd - deferred incoming control message * @node: list node * @msg: message header * data: payload of the message @@ -95,15 +95,15 @@ struct glink_msg { * Copy of a received control message, to be added to @rx_queue and processed * by @rx_work of @glink_spi. */ -struct glink_defer_cmd { +struct glink_spi_defer_cmd { struct list_head node; - struct glink_msg msg; + struct glink_spi_msg msg; u8 data[]; }; /** - * struct glink_core_rx_intent - RX intent + * struct glink_spi_rx_intent - RX intent * RX intent * * @data: pointer to the data (may be NULL for zero-copy) @@ -114,7 +114,7 @@ struct glink_defer_cmd { * @in_use: To mark if intent is already in use for the channel * @offset: next write offset (initially 0) */ -struct glink_core_rx_intent { +struct glink_spi_rx_intent { void *data; u32 id; size_t size; @@ -214,7 +214,7 @@ enum { }; /** - * struct glink_channel - internal representation of a channel + * struct glink_spi_channel - internal representation of a channel * @rpdev: rpdev reference, only used for primary endpoints * @ept: rpmsg endpoint this channel is associated with * @glink: glink_spi context handle @@ -237,7 +237,7 @@ enum { * @intent_req_result: Result of intent request * @intent_req_comp: Completion for intent_req signalling */ -struct glink_channel { +struct glink_spi_channel { struct rpmsg_endpoint ept; struct rpmsg_device *rpdev; @@ -257,7 +257,7 @@ struct glink_channel { struct work_struct intent_work; struct list_head done_intents; - struct glink_core_rx_intent *buf; + struct glink_spi_rx_intent *buf; int buf_offset; int buf_size; @@ -272,7 +272,7 @@ struct glink_channel { struct completion intent_req_comp; }; -#define to_glink_channel(_ept) container_of(_ept, struct glink_channel, ept) +#define to_glink_channel(_ept) container_of(_ept, struct glink_spi_channel, ept) static const struct rpmsg_endpoint_ops glink_endpoint_ops; @@ -337,16 +337,16 @@ static void glink_spi_xprt_set_irq_mode(struct glink_spi *glink) atomic_dec(&glink->activity_cnt); } -static struct glink_channel *glink_spi_alloc_channel(struct glink_spi *glink, - const char *name) +static struct glink_spi_channel * +glink_spi_alloc_channel(struct glink_spi *glink, const char *name) { - struct glink_channel *channel; + struct glink_spi_channel *channel; channel = kzalloc(sizeof(*channel), GFP_KERNEL); if (!channel) return ERR_PTR(-ENOMEM); - /* Setup glink internal glink_channel data */ + /* Setup glink internal glink_spi_channel data */ spin_lock_init(&channel->recv_lock); spin_lock_init(&channel->intent_lock); mutex_init(&channel->intent_req_lock); @@ -370,11 +370,12 @@ static struct glink_channel *glink_spi_alloc_channel(struct glink_spi *glink, static void glink_spi_channel_release(struct kref *ref) { - struct glink_channel *channel = container_of(ref, struct glink_channel, - refcount); + struct glink_spi_channel *channel; unsigned long flags; + channel = container_of(ref, struct glink_spi_channel, refcount); CH_INFO(channel, "\n"); + spin_lock_irqsave(&channel->intent_lock, flags); idr_destroy(&channel->liids); idr_destroy(&channel->riids); @@ -679,7 +680,7 @@ static int glink_spi_tx(struct glink_spi *glink, void *hdr, size_t hlen, static int glink_spi_send_version(struct glink_spi *glink) { - struct glink_msg msg = { 0 }; + struct glink_spi_msg msg = { 0 }; msg.cmd = cpu_to_le16(SPI_CMD_VERSION); msg.param1 = cpu_to_le16(GLINK_VERSION_1); @@ -691,7 +692,7 @@ static int glink_spi_send_version(struct glink_spi *glink) static void glink_spi_send_version_ack(struct glink_spi *glink) { - struct glink_msg msg = { 0 }; + struct glink_spi_msg msg = { 0 }; msg.cmd = cpu_to_le16(SPI_CMD_VERSION_ACK); msg.param1 = cpu_to_le16(GLINK_VERSION_1); @@ -773,7 +774,7 @@ static void glink_spi_receive_version_ack(struct glink_spi *glink, * Returns 0 on success, negative errno otherwise. */ static int glink_spi_send_open_req(struct glink_spi *glink, - struct glink_channel *channel) + struct glink_spi_channel *channel) { struct cmd_msg { @@ -829,9 +830,9 @@ static int glink_spi_send_open_req(struct glink_spi *glink, } static void glink_spi_send_open_ack(struct glink_spi *glink, - struct glink_channel *channel) + struct glink_spi_channel *channel) { - struct glink_msg msg = { 0 }; + struct glink_spi_msg msg = { 0 }; msg.cmd = cpu_to_le16(SPI_CMD_OPEN_ACK); msg.param1 = cpu_to_le16(channel->rcid); @@ -842,7 +843,7 @@ static void glink_spi_send_open_ack(struct glink_spi *glink, static int glink_spi_rx_open_ack(struct glink_spi *glink, unsigned int lcid) { - struct glink_channel *channel; + struct glink_spi_channel *channel; spin_lock(&glink->idr_lock); channel = idr_find(&glink->lcids, lcid); @@ -859,9 +860,9 @@ static int glink_spi_rx_open_ack(struct glink_spi *glink, unsigned int lcid) } static void glink_spi_send_close_req(struct glink_spi *glink, - struct glink_channel *channel) + struct glink_spi_channel *channel) { - struct glink_msg req = { 0 }; + struct glink_spi_msg req = { 0 }; req.cmd = cpu_to_le16(SPI_CMD_CLOSE); req.param1 = cpu_to_le16(channel->lcid); @@ -873,7 +874,7 @@ static void glink_spi_send_close_req(struct glink_spi *glink, static void glink_spi_send_close_ack(struct glink_spi *glink, unsigned int rcid) { - struct glink_msg req = { 0 }; + struct glink_spi_msg req = { 0 }; req.cmd = cpu_to_le16(SPI_CMD_CLOSE_ACK); req.param1 = cpu_to_le16(rcid); @@ -883,10 +884,10 @@ static void glink_spi_send_close_ack(struct glink_spi *glink, } static int glink_spi_request_intent(struct glink_spi *glink, - struct glink_channel *channel, + struct glink_spi_channel *channel, size_t size) { - struct glink_msg req = { 0 }; + struct glink_spi_msg req = { 0 }; int ret; mutex_lock(&channel->intent_req_lock); @@ -922,8 +923,8 @@ static int glink_spi_handle_intent(struct glink_spi *glink, void *rx_data, size_t avail) { - struct glink_core_rx_intent *intent; - struct glink_channel *channel; + struct glink_spi_rx_intent *intent; + struct glink_spi_channel *channel; struct intent_pair { __le32 size; __le32 iid; @@ -975,7 +976,7 @@ static int glink_spi_handle_intent(struct glink_spi *glink, static void glink_spi_handle_intent_req_ack(struct glink_spi *glink, unsigned int cid, bool granted) { - struct glink_channel *channel; + struct glink_spi_channel *channel; unsigned long flags; spin_lock_irqsave(&glink->idr_lock, flags); @@ -1001,10 +1002,10 @@ static void glink_spi_handle_intent_req_ack(struct glink_spi *glink, * Return: 0 on success or standard Linux error code. */ static int glink_spi_send_intent_req_ack(struct glink_spi *glink, - struct glink_channel *channel, + struct glink_spi_channel *channel, bool granted) { - struct glink_msg msg = { 0 }; + struct glink_spi_msg msg = { 0 }; msg.cmd = cpu_to_le16(SPI_CMD_RX_INTENT_REQ_ACK); msg.param1 = cpu_to_le16(channel->lcid); @@ -1016,13 +1017,13 @@ static int glink_spi_send_intent_req_ack(struct glink_spi *glink, return 0; } -static struct glink_core_rx_intent * +static struct glink_spi_rx_intent * glink_spi_alloc_intent(struct glink_spi *glink, - struct glink_channel *channel, + struct glink_spi_channel *channel, size_t size, bool reuseable) { - struct glink_core_rx_intent *intent; + struct glink_spi_rx_intent *intent; int ret; unsigned long flags; @@ -1065,11 +1066,11 @@ glink_spi_alloc_intent(struct glink_spi *glink, * Return: 0 on success or standard Linux error code. */ static int glink_spi_advertise_intent(struct glink_spi *glink, - struct glink_channel *channel, - struct glink_core_rx_intent *intent) + struct glink_spi_channel *channel, + struct glink_spi_rx_intent *intent) { struct command { - struct glink_msg msg; + struct glink_spi_msg msg; __le32 size; __le32 liid; __le64 addr; @@ -1104,8 +1105,8 @@ static int glink_spi_advertise_intent(struct glink_spi *glink, static void glink_spi_handle_intent_req(struct glink_spi *glink, u32 cid, size_t size) { - struct glink_core_rx_intent *intent; - struct glink_channel *channel; + struct glink_spi_rx_intent *intent; + struct glink_spi_channel *channel; unsigned long flags; spin_lock_irqsave(&glink->idr_lock, flags); @@ -1124,13 +1125,13 @@ static void glink_spi_handle_intent_req(struct glink_spi *glink, glink_spi_send_intent_req_ack(glink, channel, !!intent); } -static int glink_spi_send_short(struct glink_channel *channel, +static int glink_spi_send_short(struct glink_spi_channel *channel, void *data, int len, - struct glink_core_rx_intent *intent, bool wait) + struct glink_spi_rx_intent *intent, bool wait) { struct glink_spi *glink = channel->glink; struct { - struct glink_msg msg; + struct glink_spi_msg msg; u8 data[SHORT_SIZE]; } __packed req; @@ -1168,13 +1169,13 @@ static int glink_spi_send_short(struct glink_channel *channel, return 0; } -static int glink_spi_send_data(struct glink_channel *channel, +static int glink_spi_send_data(struct glink_spi_channel *channel, void *data, int chunk_size, int left_size, - struct glink_core_rx_intent *intent, bool wait) + struct glink_spi_rx_intent *intent, bool wait) { struct glink_spi *glink = channel->glink; struct { - struct glink_msg msg; + struct glink_spi_msg msg; __le32 chunk_size; __le32 left_size; } __packed req; @@ -1219,12 +1220,12 @@ static int glink_spi_send_data(struct glink_channel *channel, return 0; } -static int __glink_spi_send(struct glink_channel *channel, +static int __glink_spi_send(struct glink_spi_channel *channel, void *data, int len, bool wait) { struct glink_spi *glink = channel->glink; - struct glink_core_rx_intent *intent = NULL; - struct glink_core_rx_intent *tmp; + struct glink_spi_rx_intent *intent = NULL; + struct glink_spi_rx_intent *tmp; int size = len; int iid = 0; int ret = 0; @@ -1295,8 +1296,8 @@ static void glink_spi_handle_rx_done(struct glink_spi *glink, u32 cid, uint32_t iid, bool reuse) { - struct glink_core_rx_intent *intent; - struct glink_channel *channel; + struct glink_spi_rx_intent *intent; + struct glink_spi_channel *channel; unsigned long flags; spin_lock_irqsave(&glink->idr_lock, flags); @@ -1328,9 +1329,9 @@ static void glink_spi_handle_rx_done(struct glink_spi *glink, } static int __glink_spi_rx_done(struct glink_spi *glink, - struct glink_channel *channel, - struct glink_core_rx_intent *intent, - bool wait) + struct glink_spi_channel *channel, + struct glink_spi_rx_intent *intent, + bool wait) { struct { u16 id; @@ -1363,12 +1364,14 @@ static int __glink_spi_rx_done(struct glink_spi *glink, static void glink_spi_rx_done_work(struct work_struct *work) { - struct glink_channel *channel = container_of(work, struct glink_channel, - intent_work); - struct glink_spi *glink = channel->glink; - struct glink_core_rx_intent *intent, *tmp; + struct glink_spi_channel *channel; + struct glink_spi *glink; + struct glink_spi_rx_intent *intent, *tmp; unsigned long flags; + channel = container_of(work, struct glink_spi_channel, intent_work); + glink = channel->glink; + atomic_inc(&glink->activity_cnt); spi_resume(&glink->cmpnt); @@ -1387,8 +1390,8 @@ static void glink_spi_rx_done_work(struct work_struct *work) } static void glink_spi_rx_done(struct glink_spi *glink, - struct glink_channel *channel, - struct glink_core_rx_intent *intent) + struct glink_spi_channel *channel, + struct glink_spi_rx_intent *intent) { unsigned long flags; int ret = -EAGAIN; @@ -1420,10 +1423,10 @@ static void glink_spi_rx_done(struct glink_spi *glink, } /* Locally initiated rpmsg_create_ept */ -static struct glink_channel *glink_spi_create_local(struct glink_spi *glink, - const char *name) +static struct glink_spi_channel *glink_spi_create_local(struct glink_spi *glink, + const char *name) { - struct glink_channel *channel; + struct glink_spi_channel *channel; int ret; unsigned long flags; @@ -1468,7 +1471,7 @@ static struct glink_channel *glink_spi_create_local(struct glink_spi *glink, /* Remote initiated rpmsg_create_ept */ static int glink_spi_create_remote(struct glink_spi *glink, - struct glink_channel *channel) + struct glink_spi_channel *channel) { int ret; @@ -1502,14 +1505,12 @@ static int glink_spi_create_remote(struct glink_spi *glink, return ret; } -static struct rpmsg_endpoint *glink_spi_create_ept(struct rpmsg_device *rpdev, - rpmsg_rx_cb_t cb, - void *priv, - struct rpmsg_channel_info - chinfo) +static struct rpmsg_endpoint * +glink_spi_create_ept(struct rpmsg_device *rpdev, rpmsg_rx_cb_t cb, void *priv, + struct rpmsg_channel_info chinfo) { - struct glink_channel *parent = to_glink_channel(rpdev->ept); - struct glink_channel *channel; + struct glink_spi_channel *parent = to_glink_channel(rpdev->ept); + struct glink_spi_channel *channel; struct glink_spi *glink = parent->glink; struct rpmsg_endpoint *ept; const char *name = chinfo.name; @@ -1545,10 +1546,10 @@ static struct rpmsg_endpoint *glink_spi_create_ept(struct rpmsg_device *rpdev, static int glink_spi_announce_create(struct rpmsg_device *rpdev) { - struct glink_channel *channel = to_glink_channel(rpdev->ept); + struct glink_spi_channel *channel = to_glink_channel(rpdev->ept); struct device_node *np = rpdev->dev.of_node; struct glink_spi *glink = channel->glink; - struct glink_core_rx_intent *intent; + struct glink_spi_rx_intent *intent; const struct property *prop = NULL; __be32 defaults[] = { cpu_to_be32(SZ_1K), cpu_to_be32(5) }; int num_intents; @@ -1583,7 +1584,7 @@ static int glink_spi_announce_create(struct rpmsg_device *rpdev) static void glink_spi_destroy_ept(struct rpmsg_endpoint *ept) { - struct glink_channel *channel = to_glink_channel(ept); + struct glink_spi_channel *channel = to_glink_channel(ept); struct glink_spi *glink = channel->glink; unsigned long flags; @@ -1600,7 +1601,7 @@ static void glink_spi_destroy_ept(struct rpmsg_endpoint *ept) static void glink_spi_rx_close(struct glink_spi *glink, unsigned int rcid) { struct rpmsg_channel_info chinfo; - struct glink_channel *channel; + struct glink_spi_channel *channel; unsigned long flags; spin_lock_irqsave(&glink->idr_lock, flags); @@ -1633,7 +1634,7 @@ static void glink_spi_rx_close(struct glink_spi *glink, unsigned int rcid) static void glink_spi_rx_close_ack(struct glink_spi *glink, unsigned int lcid) { - struct glink_channel *channel; + struct glink_spi_channel *channel; unsigned long flags; spin_lock_irqsave(&glink->idr_lock, flags); @@ -1653,14 +1654,14 @@ static void glink_spi_rx_close_ack(struct glink_spi *glink, unsigned int lcid) static int glink_spi_send(struct rpmsg_endpoint *ept, void *data, int len) { - struct glink_channel *channel = to_glink_channel(ept); + struct glink_spi_channel *channel = to_glink_channel(ept); return __glink_spi_send(channel, data, len, true); } static int glink_spi_trysend(struct rpmsg_endpoint *ept, void *data, int len) { - struct glink_channel *channel = to_glink_channel(ept); + struct glink_spi_channel *channel = to_glink_channel(ept); return __glink_spi_send(channel, data, len, false); } @@ -1674,10 +1675,10 @@ static int glink_spi_trysend(struct rpmsg_endpoint *ept, void *data, int len) * Return: 0 on success or standard Linux error code. */ static int glink_spi_send_signals(struct glink_spi *glink, - struct glink_channel *channel, + struct glink_spi_channel *channel, u32 sigs) { - struct glink_msg msg; + struct glink_spi_msg msg; msg.cmd = cpu_to_le16(SPI_CMD_SIGNALS); msg.param1 = cpu_to_le16(channel->lcid); @@ -1690,7 +1691,7 @@ static int glink_spi_send_signals(struct glink_spi *glink, static int glink_spi_handle_signals(struct glink_spi *glink, unsigned int rcid, unsigned int signals) { - struct glink_channel *channel; + struct glink_spi_channel *channel; unsigned long flags; u32 old; @@ -1716,7 +1717,7 @@ static int glink_spi_handle_signals(struct glink_spi *glink, static int glink_spi_get_sigs(struct rpmsg_endpoint *ept, u32 *lsigs, u32 *rsigs) { - struct glink_channel *channel = to_glink_channel(ept); + struct glink_spi_channel *channel = to_glink_channel(ept); *lsigs = channel->lsigs; *rsigs = channel->rsigs; @@ -1726,7 +1727,7 @@ static int glink_spi_get_sigs(struct rpmsg_endpoint *ept, static int glink_spi_set_sigs(struct rpmsg_endpoint *ept, u32 sigs) { - struct glink_channel *channel = to_glink_channel(ept); + struct glink_spi_channel *channel = to_glink_channel(ept); struct glink_spi *glink = channel->glink; channel->lsigs = sigs; @@ -1774,16 +1775,16 @@ static const struct rpmsg_endpoint_ops glink_endpoint_ops = { static void glink_spi_rpdev_release(struct device *dev) { struct rpmsg_device *rpdev = to_rpmsg_device(dev); - struct glink_channel *channel = to_glink_channel(rpdev->ept); + struct glink_spi_channel *channel = to_glink_channel(rpdev->ept); channel->rpdev = NULL; kfree(rpdev); } static int glink_spi_rx_open(struct glink_spi *glink, unsigned int rcid, - char *name) + char *name) { - struct glink_channel *channel; + struct glink_spi_channel *channel; struct rpmsg_device *rpdev; bool create_device = false; struct device_node *node; @@ -1869,8 +1870,8 @@ static int glink_spi_rx_data(struct glink_spi *glink, unsigned int rcid, unsigned int liid, void *rx_data, size_t avail) { - struct glink_core_rx_intent *intent; - struct glink_channel *channel; + struct glink_spi_rx_intent *intent; + struct glink_spi_channel *channel; struct data_desc { __le32 chunk_size; __le32 left_size; @@ -1951,8 +1952,8 @@ static int glink_spi_rx_short_data(struct glink_spi *glink, unsigned int left_size, void *src, size_t avail) { - struct glink_core_rx_intent *intent; - struct glink_channel *channel; + struct glink_spi_rx_intent *intent; + struct glink_spi_channel *channel; size_t msglen = SHORT_SIZE; unsigned long flags; @@ -2016,8 +2017,8 @@ static void glink_spi_defer_work(struct work_struct *work) struct glink_spi *glink = container_of(work, struct glink_spi, rx_defer_work); - struct glink_defer_cmd *dcmd; - struct glink_msg *msg; + struct glink_spi_defer_cmd *dcmd; + struct glink_spi_msg *msg; unsigned long flags; unsigned int param1; unsigned int param2; @@ -2034,7 +2035,7 @@ static void glink_spi_defer_work(struct work_struct *work) break; } dcmd = list_first_entry(&glink->rx_queue, - struct glink_defer_cmd, node); + struct glink_spi_defer_cmd, node); list_del(&dcmd->node); spin_unlock_irqrestore(&glink->rx_lock, flags); @@ -2068,11 +2069,11 @@ static void glink_spi_defer_work(struct work_struct *work) static int glink_spi_rx_defer(struct glink_spi *glink, void *rx_data, u32 rx_avail, size_t extra) { - struct glink_defer_cmd *dcmd; + struct glink_spi_defer_cmd *dcmd; extra = ALIGN(extra, SPI_ALIGNMENT); - if (rx_avail < sizeof(struct glink_msg) + extra) { + if (rx_avail < sizeof(struct glink_spi_msg) + extra) { dev_dbg(&glink->dev, "Insufficient data in rx fifo"); return -ENXIO; } @@ -2097,7 +2098,7 @@ static int glink_spi_rx_defer(struct glink_spi *glink, static void glink_spi_process_cmd(struct glink_spi *glink, void *rx_data, u32 rx_size) { - struct glink_msg *msg; + struct glink_spi_msg *msg; unsigned int param1; unsigned int param2; unsigned int param3; @@ -2109,7 +2110,7 @@ static void glink_spi_process_cmd(struct glink_spi *glink, void *rx_data, char *name; while (offset < rx_size) { - msg = (struct glink_msg *)(rx_data + offset); + msg = (struct glink_spi_msg *)(rx_data + offset); offset += sizeof(*msg); cmd = le16_to_cpu(msg->cmd); @@ -2359,7 +2360,7 @@ static void glink_spi_release(struct device *dev) } struct glink_spi *qcom_glink_spi_register(struct device *parent, - struct device_node *node) + struct device_node *node) { struct glink_spi *glink; struct device *dev; @@ -2448,7 +2449,7 @@ static void glink_spi_remove(struct glink_spi *glink) { struct glink_spi_pipe *rx_pipe = &glink->rx_pipe; struct glink_spi_pipe *tx_pipe = &glink->tx_pipe; - struct glink_channel *channel; + struct glink_spi_channel *channel; int cid; int ret; unsigned long flags; diff --git a/drivers/rtc/rtc-bq4802.c b/drivers/rtc/rtc-bq4802.c index bd170cb3361ce15e511a3a81f2ff1c06a5ed3bfe..5747a54cbd423e34c13e5f920ee7f8bce1cc2c50 100644 --- a/drivers/rtc/rtc-bq4802.c +++ b/drivers/rtc/rtc-bq4802.c @@ -164,6 +164,10 @@ static int bq4802_probe(struct platform_device *pdev) } else if (p->r->flags & IORESOURCE_MEM) { p->regs = devm_ioremap(&pdev->dev, p->r->start, resource_size(p->r)); + if (!p->regs){ + err = -ENOMEM; + goto out; + } p->read = bq4802_read_mem; p->write = bq4802_write_mem; } else { diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 13f7cd11c07eb52948121225242b57f8ab2c8e2c..ac6e6a6a194c71de44bde323135e0cca8780921b 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -817,13 +817,6 @@ static int omap_rtc_probe(struct platform_device *pdev) goto err; } - if (rtc->is_pmic_controller) { - if (!pm_power_off) { - omap_rtc_power_off_rtc = rtc; - pm_power_off = omap_rtc_power_off; - } - } - /* Support ext_wakeup pinconf */ rtc_pinctrl_desc.name = dev_name(&pdev->dev); @@ -833,6 +826,13 @@ static int omap_rtc_probe(struct platform_device *pdev) return PTR_ERR(rtc->pctldev); } + if (rtc->is_pmic_controller) { + if (!pm_power_off) { + omap_rtc_power_off_rtc = rtc; + pm_power_off = omap_rtc_power_off; + } + } + return 0; err: diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index d072f84a8535f160889eca5891370747e67b03c8..92c4f5180ad07914e8c2722988b8f8e2f32fff17 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -3190,6 +3190,7 @@ static int dasd_alloc_queue(struct dasd_block *block) block->tag_set.nr_hw_queues = DASD_NR_HW_QUEUES; block->tag_set.queue_depth = DASD_MAX_LCU_DEV * DASD_REQ_PER_DEV; block->tag_set.flags = BLK_MQ_F_SHOULD_MERGE; + block->tag_set.numa_node = NUMA_NO_NODE; rc = blk_mq_alloc_tag_set(&block->tag_set); if (rc) diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 5ede251c52ca980e51f6e22fdbfc3bef08c5c9c6..4c7c8455da961422c8a92f9c8862fb8a59c16132 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1778,6 +1778,9 @@ static void dasd_eckd_uncheck_device(struct dasd_device *device) struct dasd_eckd_private *private = device->private; int i; + if (!private) + return; + dasd_alias_disconnect_device_from_lcu(device); private->ned = NULL; private->sneq = NULL; @@ -2032,8 +2035,11 @@ static int dasd_eckd_basic_to_ready(struct dasd_device *device) static int dasd_eckd_online_to_ready(struct dasd_device *device) { - cancel_work_sync(&device->reload_device); - cancel_work_sync(&device->kick_validate); + if (cancel_work_sync(&device->reload_device)) + dasd_put_device(device); + if (cancel_work_sync(&device->kick_validate)) + dasd_put_device(device); + return 0; }; diff --git a/drivers/s390/block/scm_blk.c b/drivers/s390/block/scm_blk.c index eb51893c74a4ba4053fe8d15e064fbf42bed9845..5c944ee76ec1494c0515c5dee9aa80bc5da096df 100644 --- a/drivers/s390/block/scm_blk.c +++ b/drivers/s390/block/scm_blk.c @@ -454,6 +454,7 @@ int scm_blk_dev_setup(struct scm_blk_dev *bdev, struct scm_device *scmdev) bdev->tag_set.nr_hw_queues = nr_requests; bdev->tag_set.queue_depth = nr_requests_per_io * nr_requests; bdev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE; + bdev->tag_set.numa_node = NUMA_NO_NODE; ret = blk_mq_alloc_tag_set(&bdev->tag_set); if (ret) diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 8941e7caaf4dc9c3ae180569329457f5342d1ae8..c7afdbded26b6bfefd82dd8db3c643c5c931f857 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -641,21 +641,20 @@ static inline unsigned long qdio_aob_for_buffer(struct qdio_output_q *q, unsigned long phys_aob = 0; if (!q->use_cq) - goto out; + return 0; if (!q->aobs[bufnr]) { struct qaob *aob = qdio_allocate_aob(); q->aobs[bufnr] = aob; } if (q->aobs[bufnr]) { - q->sbal_state[bufnr].flags = QDIO_OUTBUF_STATE_FLAG_NONE; q->sbal_state[bufnr].aob = q->aobs[bufnr]; q->aobs[bufnr]->user1 = (u64) q->sbal_state[bufnr].user; phys_aob = virt_to_phys(q->aobs[bufnr]); WARN_ON_ONCE(phys_aob & 0xFF); } -out: + q->sbal_state[bufnr].flags = 0; return phys_aob; } diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c index 82f05c4b8c526f73a52aed819eacb33cdfd18e3a..ae7a49ade414bd8e33356f47e954cfc27a2488a3 100644 --- a/drivers/s390/cio/vfio_ccw_drv.c +++ b/drivers/s390/cio/vfio_ccw_drv.c @@ -176,6 +176,7 @@ static int vfio_ccw_sch_event(struct subchannel *sch, int process) { struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev); unsigned long flags; + int rc = -EAGAIN; spin_lock_irqsave(sch->lock, flags); if (!device_is_registered(&sch->dev)) @@ -186,6 +187,7 @@ static int vfio_ccw_sch_event(struct subchannel *sch, int process) if (cio_update_schib(sch)) { vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_NOT_OPER); + rc = 0; goto out_unlock; } @@ -194,11 +196,12 @@ static int vfio_ccw_sch_event(struct subchannel *sch, int process) private->state = private->mdev ? VFIO_CCW_STATE_IDLE : VFIO_CCW_STATE_STANDBY; } + rc = 0; out_unlock: spin_unlock_irqrestore(sch->lock, flags); - return 0; + return rc; } static struct css_device_id vfio_ccw_sch_ids[] = { diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 939b5b5e97efe81ad52a04ab04b678d0fc424ee5..4f2747cd15a624624a4ac11f5a4738be5723ccc5 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -3507,13 +3508,14 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, qdio_flags = QDIO_FLAG_SYNC_OUTPUT; if (atomic_read(&queue->set_pci_flags_count)) qdio_flags |= QDIO_FLAG_PCI_OUT; + atomic_add(count, &queue->used_buffers); + rc = do_QDIO(CARD_DDEV(queue->card), qdio_flags, queue->queue_no, index, count); if (queue->card->options.performance_stats) queue->card->perf_stats.outbound_do_qdio_time += qeth_get_micros() - queue->card->perf_stats.outbound_do_qdio_start_time; - atomic_add(count, &queue->used_buffers); if (rc) { queue->card->stats.tx_errors += count; /* ignore temporary SIGA errors without busy condition */ @@ -4727,7 +4729,7 @@ static int qeth_query_oat_command(struct qeth_card *card, char __user *udata) priv.buffer_len = oat_data.buffer_len; priv.response_len = 0; - priv.buffer = kzalloc(oat_data.buffer_len, GFP_KERNEL); + priv.buffer = vzalloc(oat_data.buffer_len); if (!priv.buffer) { rc = -ENOMEM; goto out; @@ -4768,7 +4770,7 @@ static int qeth_query_oat_command(struct qeth_card *card, char __user *udata) rc = -EFAULT; out_free: - kfree(priv.buffer); + vfree(priv.buffer); out: return rc; } diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index d1ee9e30c68bec45fba048ae30c4ae325fc5f2d0..21e91fbb28605399116a1144cfced5ea27f57fd4 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c @@ -423,6 +423,7 @@ static ssize_t qeth_dev_layer2_store(struct device *dev, if (card->discipline) { card->discipline->remove(card->gdev); qeth_core_free_discipline(card); + card->options.layer2 = -1; } rc = qeth_core_load_discipline(card, newdis); diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 521293b1f4fab1d4edea33d175328b55b1a636a9..11ae67842edf0bab9f28e0236adcc50e94545885 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -484,7 +484,7 @@ static int qeth_l2_process_inbound_buffer(struct qeth_card *card, default: dev_kfree_skb_any(skb); QETH_CARD_TEXT(card, 3, "inbunkno"); - QETH_DBF_HEX(CTRL, 3, hdr, QETH_DBF_CTRL_LEN); + QETH_DBF_HEX(CTRL, 3, hdr, sizeof(*hdr)); continue; } work_done++; diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 1c62cbbaa66f60106c30ec37bcc7e6bf01d72c11..cd73172bff477a3eb104a855ced58ffd3e4cf672 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -1793,7 +1793,7 @@ static int qeth_l3_process_inbound_buffer(struct qeth_card *card, default: dev_kfree_skb_any(skb); QETH_CARD_TEXT(card, 3, "inbunkno"); - QETH_DBF_HEX(CTRL, 3, hdr, QETH_DBF_CTRL_LEN); + QETH_DBF_HEX(CTRL, 3, hdr, sizeof(*hdr)); continue; } work_done++; diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index a1388842e17e561e901726ccb61bc44163332c24..dd342207095af001581bce325583e0c991339d45 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -2042,6 +2042,7 @@ static int twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) if (twa_initialize_device_extension(tw_dev)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x25, "Failed to initialize device extension"); + retval = -ENOMEM; goto out_free_device_extension; } @@ -2064,6 +2065,7 @@ static int twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) tw_dev->base_addr = ioremap(mem_addr, mem_len); if (!tw_dev->base_addr) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x35, "Failed to ioremap"); + retval = -ENOMEM; goto out_release_mem_region; } @@ -2071,8 +2073,10 @@ static int twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) TW_DISABLE_INTERRUPTS(tw_dev); /* Initialize the card */ - if (twa_reset_sequence(tw_dev, 0)) + if (twa_reset_sequence(tw_dev, 0)) { + retval = -ENOMEM; goto out_iounmap; + } /* Set host specific parameters */ if ((pdev->device == PCI_DEVICE_ID_3WARE_9650SE) || diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c index b150e131b2e76a172aa13bbf84949ec0cc269cd4..aa317d6909e8f0ea71196ad0cedd5337e10f87e4 100644 --- a/drivers/scsi/3w-sas.c +++ b/drivers/scsi/3w-sas.c @@ -1597,6 +1597,7 @@ static int twl_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) if (twl_initialize_device_extension(tw_dev)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1a, "Failed to initialize device extension"); + retval = -ENOMEM; goto out_free_device_extension; } @@ -1611,6 +1612,7 @@ static int twl_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) tw_dev->base_addr = pci_iomap(pdev, 1, 0); if (!tw_dev->base_addr) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to ioremap"); + retval = -ENOMEM; goto out_release_mem_region; } @@ -1620,6 +1622,7 @@ static int twl_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) /* Initialize the card */ if (twl_reset_sequence(tw_dev, 0)) { TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1d, "Controller reset failed during probe"); + retval = -ENOMEM; goto out_iounmap; } diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index f6179e3d695397e368cdd57e913d8863e829fa31..961ea6f7def87263e314d389a6b33b3b34a883e1 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -2280,6 +2280,7 @@ static int tw_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) if (tw_initialize_device_extension(tw_dev)) { printk(KERN_WARNING "3w-xxxx: Failed to initialize device extension."); + retval = -ENOMEM; goto out_free_device_extension; } @@ -2294,6 +2295,7 @@ static int tw_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) tw_dev->base_addr = pci_resource_start(pdev, 0); if (!tw_dev->base_addr) { printk(KERN_WARNING "3w-xxxx: Failed to get io address."); + retval = -ENOMEM; goto out_release_mem_region; } diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index 6c838865ac5a7b32fd853aa36a07611e9809adc3..4a4746cc6745f2cc95b2ce0e570a7df05fc77484 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -1030,8 +1030,10 @@ static int __init aic94xx_init(void) aic94xx_transport_template = sas_domain_attach_transport(&aic94xx_transport_functions); - if (!aic94xx_transport_template) + if (!aic94xx_transport_template) { + err = -ENOMEM; goto out_destroy_caches; + } err = pci_register_driver(&aic94xx_pci_driver); if (err) diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c index 42921dbba9272f793a2a4a483e727dfa78809e4b..4ca10501647b33573af8ef917810e7c199b97e4d 100644 --- a/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/drivers/scsi/bnx2i/bnx2i_hwi.c @@ -2742,6 +2742,8 @@ int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep) BNX2X_DOORBELL_PCI_BAR); reg_off = (1 << BNX2X_DB_SHIFT) * (cid_num & 0x1FFFF); ep->qp.ctx_base = ioremap_nocache(reg_base + reg_off, 4); + if (!ep->qp.ctx_base) + return -ENOMEM; goto arm_cq; } diff --git a/drivers/scsi/csiostor/csio_hw.c b/drivers/scsi/csiostor/csio_hw.c index 5be0086142cac6991598cd9099522212709a216c..ab30db8c36c6fe561a22ba49fff11d568a0680c5 100644 --- a/drivers/scsi/csiostor/csio_hw.c +++ b/drivers/scsi/csiostor/csio_hw.c @@ -2010,8 +2010,8 @@ static int csio_hw_prep_fw(struct csio_hw *hw, struct fw_info *fw_info, } /* - * Returns -EINVAL if attempts to flash the firmware failed - * else returns 0, + * Returns -EINVAL if attempts to flash the firmware failed, + * -ENOMEM if memory allocation failed else returns 0, * if flashing was not attempted because the card had the * latest firmware ECANCELED is returned */ @@ -2039,6 +2039,13 @@ csio_hw_flash_fw(struct csio_hw *hw, int *reset) return -EINVAL; } + /* allocate memory to read the header of the firmware on the + * card + */ + card_fw = kmalloc(sizeof(*card_fw), GFP_KERNEL); + if (!card_fw) + return -ENOMEM; + if (csio_is_t5(pci_dev->device & CSIO_HW_CHIP_MASK)) fw_bin_file = FW_FNAME_T5; else @@ -2052,11 +2059,6 @@ csio_hw_flash_fw(struct csio_hw *hw, int *reset) fw_size = fw->size; } - /* allocate memory to read the header of the firmware on the - * card - */ - card_fw = kmalloc(sizeof(*card_fw), GFP_KERNEL); - /* upgrade FW logic */ ret = csio_hw_prep_fw(hw, fw_info, fw_data, fw_size, card_fw, hw->fw_state, reset); diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index fff6f1851dc1e56779acff511c5b6c3625a9f51c..03019e07abb96443fbdb21653c27eb4d7864091e 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -754,9 +754,9 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport, case ELS_LOGO: if (fip->mode == FIP_MODE_VN2VN) { if (fip->state != FIP_ST_VNMP_UP) - return -EINVAL; + goto drop; if (ntoh24(fh->fh_d_id) == FC_FID_FLOGI) - return -EINVAL; + goto drop; } else { if (fip->state != FIP_ST_ENABLED) return 0; @@ -799,9 +799,9 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport, fip->send(fip, skb); return -EINPROGRESS; drop: - kfree_skb(skb); LIBFCOE_FIP_DBG(fip, "drop els_send op %u d_id %x\n", op, ntoh24(fh->fh_d_id)); + kfree_skb(skb); return -EINVAL; } EXPORT_SYMBOL(fcoe_ctlr_els_send); diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index dd9464920456fd550f8da9bab2e345ae843d1d15..ef22b275d0505b5bd9580182b2c67730f3181dc8 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -474,6 +474,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) shost->dma_boundary = 0xffffffff; shost->use_blk_mq = scsi_use_blk_mq; + shost->use_blk_mq = scsi_use_blk_mq || shost->hostt->force_blk_mq; device_initialize(&shost->shost_gendev); dev_set_name(&shost->shost_gendev, "host%d", shost->host_no); diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 604a39dba5d0c7d0a0a54ed4267efeb09ae88b0e..5b4b7f9be2d749da9e8ca2e42b4f51196476d473 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1040,11 +1040,7 @@ static void set_performant_mode(struct ctlr_info *h, struct CommandList *c, c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1); if (unlikely(!h->msix_vectors)) return; - if (likely(reply_queue == DEFAULT_REPLY_QUEUE)) - c->Header.ReplyQueue = - raw_smp_processor_id() % h->nreply_queues; - else - c->Header.ReplyQueue = reply_queue % h->nreply_queues; + c->Header.ReplyQueue = reply_queue; } } @@ -1058,10 +1054,7 @@ static void set_ioaccel1_performant_mode(struct ctlr_info *h, * Tell the controller to post the reply to the queue for this * processor. This seems to give the best I/O throughput. */ - if (likely(reply_queue == DEFAULT_REPLY_QUEUE)) - cp->ReplyQueue = smp_processor_id() % h->nreply_queues; - else - cp->ReplyQueue = reply_queue % h->nreply_queues; + cp->ReplyQueue = reply_queue; /* * Set the bits in the address sent down to include: * - performant mode bit (bit 0) @@ -1082,10 +1075,7 @@ static void set_ioaccel2_tmf_performant_mode(struct ctlr_info *h, /* Tell the controller to post the reply to the queue for this * processor. This seems to give the best I/O throughput. */ - if (likely(reply_queue == DEFAULT_REPLY_QUEUE)) - cp->reply_queue = smp_processor_id() % h->nreply_queues; - else - cp->reply_queue = reply_queue % h->nreply_queues; + cp->reply_queue = reply_queue; /* Set the bits in the address sent down to include: * - performant mode bit not used in ioaccel mode 2 * - pull count (bits 0-3) @@ -1104,10 +1094,7 @@ static void set_ioaccel2_performant_mode(struct ctlr_info *h, * Tell the controller to post the reply to the queue for this * processor. This seems to give the best I/O throughput. */ - if (likely(reply_queue == DEFAULT_REPLY_QUEUE)) - cp->reply_queue = smp_processor_id() % h->nreply_queues; - else - cp->reply_queue = reply_queue % h->nreply_queues; + cp->reply_queue = reply_queue; /* * Set the bits in the address sent down to include: * - performant mode bit not used in ioaccel mode 2 @@ -1152,6 +1139,8 @@ static void __enqueue_cmd_and_start_io(struct ctlr_info *h, { dial_down_lockup_detection_during_fw_flash(h, c); atomic_inc(&h->commands_outstanding); + + reply_queue = h->reply_map[raw_smp_processor_id()]; switch (c->cmd_type) { case CMD_IOACCEL1: set_ioaccel1_performant_mode(h, c, reply_queue); @@ -7244,6 +7233,26 @@ static void hpsa_disable_interrupt_mode(struct ctlr_info *h) h->msix_vectors = 0; } +static void hpsa_setup_reply_map(struct ctlr_info *h) +{ + const struct cpumask *mask; + unsigned int queue, cpu; + + for (queue = 0; queue < h->msix_vectors; queue++) { + mask = pci_irq_get_affinity(h->pdev, queue); + if (!mask) + goto fallback; + + for_each_cpu(cpu, mask) + h->reply_map[cpu] = queue; + } + return; + +fallback: + for_each_possible_cpu(cpu) + h->reply_map[cpu] = 0; +} + /* If MSI/MSI-X is supported by the kernel we will try to enable it on * controllers that are capable. If not, we use legacy INTx mode. */ @@ -7639,6 +7648,10 @@ static int hpsa_pci_init(struct ctlr_info *h) err = hpsa_interrupt_mode(h); if (err) goto clean1; + + /* setup mapping between CPU and reply queue */ + hpsa_setup_reply_map(h); + err = hpsa_pci_find_memory_BAR(h->pdev, &h->paddr); if (err) goto clean2; /* intmode+region, pci */ @@ -8284,6 +8297,28 @@ static struct workqueue_struct *hpsa_create_controller_wq(struct ctlr_info *h, return wq; } +static void hpda_free_ctlr_info(struct ctlr_info *h) +{ + kfree(h->reply_map); + kfree(h); +} + +static struct ctlr_info *hpda_alloc_ctlr_info(void) +{ + struct ctlr_info *h; + + h = kzalloc(sizeof(*h), GFP_KERNEL); + if (!h) + return NULL; + + h->reply_map = kzalloc(sizeof(*h->reply_map) * nr_cpu_ids, GFP_KERNEL); + if (!h->reply_map) { + kfree(h); + return NULL; + } + return h; +} + static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { int dac, rc; @@ -8321,7 +8356,7 @@ static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) * the driver. See comments in hpsa.h for more info. */ BUILD_BUG_ON(sizeof(struct CommandList) % COMMANDLIST_ALIGNMENT); - h = kzalloc(sizeof(*h), GFP_KERNEL); + h = hpda_alloc_ctlr_info(); if (!h) { dev_err(&pdev->dev, "Failed to allocate controller head\n"); return -ENOMEM; @@ -8726,7 +8761,7 @@ static void hpsa_remove_one(struct pci_dev *pdev) h->lockup_detected = NULL; /* init_one 2 */ /* (void) pci_disable_pcie_error_reporting(pdev); */ /* init_one 1 */ - kfree(h); /* init_one 1 */ + hpda_free_ctlr_info(h); /* init_one 1 */ } static int hpsa_suspend(__attribute__((unused)) struct pci_dev *pdev, diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 018f980a701ce406e9edf0119240c39df47b9858..fb9f5e7f8209447771d07016bca7924774b143af 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -158,6 +158,7 @@ struct bmic_controller_parameters { #pragma pack() struct ctlr_info { + unsigned int *reply_map; int ctlr; char devname[8]; char *product_name; diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 7d156b161482988367ac323f8182d177421d1163..53eb277313739e982348ed2055342db7bca61c94 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -93,7 +93,7 @@ static int max_requests = IBMVSCSI_MAX_REQUESTS_DEFAULT; static int max_events = IBMVSCSI_MAX_REQUESTS_DEFAULT + 2; static int fast_fail = 1; static int client_reserve = 1; -static char partition_name[97] = "UNKNOWN"; +static char partition_name[96] = "UNKNOWN"; static unsigned int partition_number = -1; static LIST_HEAD(ibmvscsi_head); @@ -262,7 +262,7 @@ static void gather_partition_info(void) ppartition_name = of_get_property(of_root, "ibm,partition-name", NULL); if (ppartition_name) - strncpy(partition_name, ppartition_name, + strlcpy(partition_name, ppartition_name, sizeof(partition_name)); p_number_ptr = of_get_property(of_root, "ibm,partition-no", NULL); if (p_number_ptr) diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 8660f923ace02120eb63c2ac11724448d4cbd060..bb9c1c01664390a31ddb7fd225825467bf95f134 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -294,9 +294,11 @@ static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event) * discovery, reverify or log them in. Otherwise, log them out. * Skip ports which were never discovered. These are the dNS port * and ports which were created by PLOGI. + * + * We don't need to use the _rcu variant here as the rport list + * is protected by the disc mutex which is already held on entry. */ - rcu_read_lock(); - list_for_each_entry_rcu(rdata, &disc->rports, peers) { + list_for_each_entry(rdata, &disc->rports, peers) { if (!kref_get_unless_zero(&rdata->kref)) continue; if (rdata->disc_id) { @@ -307,7 +309,6 @@ static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event) } kref_put(&rdata->kref, fc_rport_destroy); } - rcu_read_unlock(); mutex_unlock(&disc->disc_mutex); disc->disc_callback(lport, event); mutex_lock(&disc->disc_mutex); diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 31d31aad3de1d3fd0f2ff58d2141cabddec474bf..89b1f1af2fd456c38e45e0a905af9a76385c1d89 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -2164,6 +2164,7 @@ static void fc_rport_recv_logo_req(struct fc_lport *lport, struct fc_frame *fp) FC_RPORT_DBG(rdata, "Received LOGO request while in state %s\n", fc_rport_state(rdata)); + rdata->flags &= ~FC_RP_STARTED; fc_rport_enter_delete(rdata, RPORT_EV_STOP); mutex_unlock(&rdata->rp_mutex); kref_put(&rdata->kref, fc_rport_destroy); diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index bddbe2da528340b930e93c49134b9ab7b5c15067..cf8a15e54d83ff7de8e01e6791a61e65749495ec 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -284,11 +284,11 @@ static int iscsi_check_tmf_restrictions(struct iscsi_task *task, int opcode) */ if (opcode != ISCSI_OP_SCSI_DATA_OUT) { iscsi_conn_printk(KERN_INFO, conn, - "task [op %x/%x itt " + "task [op %x itt " "0x%x/0x%x] " "rejected.\n", - task->hdr->opcode, opcode, - task->itt, task->hdr_itt); + opcode, task->itt, + task->hdr_itt); return -EACCES; } /* @@ -297,10 +297,10 @@ static int iscsi_check_tmf_restrictions(struct iscsi_task *task, int opcode) */ if (conn->session->fast_abort) { iscsi_conn_printk(KERN_INFO, conn, - "task [op %x/%x itt " + "task [op %x itt " "0x%x/0x%x] fast abort.\n", - task->hdr->opcode, opcode, - task->itt, task->hdr_itt); + opcode, task->itt, + task->hdr_itt); return -EACCES; } break; diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 8eb3f96fe06896ca091e634cf55b8e76819d0dec..bc61cc8bc6f0227dfb37af5bb23a279c96e19e8f 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -676,7 +676,7 @@ struct lpfc_hba { #define LS_NPIV_FAB_SUPPORTED 0x2 /* Fabric supports NPIV */ #define LS_IGNORE_ERATT 0x4 /* intr handler should ignore ERATT */ #define LS_MDS_LINK_DOWN 0x8 /* MDS Diagnostics Link Down */ -#define LS_MDS_LOOPBACK 0x16 /* MDS Diagnostics Link Up (Loopback) */ +#define LS_MDS_LOOPBACK 0x10 /* MDS Diagnostics Link Up (Loopback) */ uint32_t hba_flag; /* hba generic flags */ #define HBA_ERATT_HANDLED 0x1 /* This flag is set when eratt handled */ diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 985378e4bb6ff02ed3327bf719628508e1fee434..d55c365be2388dce37f72f30f5cc005a0153c909 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -6597,6 +6597,9 @@ megasas_resume(struct pci_dev *pdev) goto fail_init_mfi; } + if (megasas_get_ctrl_info(instance) != DCMD_SUCCESS) + goto fail_init_mfi; + tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet, (unsigned long)instance); diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c index d3940c5d079dc728ada053fc6ca6023fdd5cc02b..63dd9bc21ff2db8d01339a5196c1763b514191dc 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_transport.c +++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c @@ -1936,12 +1936,12 @@ _transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, pr_info(MPT3SAS_FMT "%s: host reset in progress!\n", __func__, ioc->name); rc = -EFAULT; - goto out; + goto job_done; } rc = mutex_lock_interruptible(&ioc->transport_cmds.mutex); if (rc) - goto out; + goto job_done; if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) { pr_err(MPT3SAS_FMT "%s: transport_cmds in use\n", ioc->name, @@ -2066,6 +2066,7 @@ _transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, out: ioc->transport_cmds.status = MPT3_CMD_NOT_USED; mutex_unlock(&ioc->transport_cmds.mutex); +job_done: bsg_job_done(job, rc, reslen); } diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index 382edb79a0de99f4bda0551cf999ec3a20a3ad56..56bcdd412d268ad6c6ea6d11b960422eef08344d 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -3240,6 +3240,11 @@ static int __qedf_probe(struct pci_dev *pdev, int mode) init_completion(&qedf->flogi_compl); + status = qed_ops->common->update_drv_state(qedf->cdev, true); + if (status) + QEDF_ERR(&(qedf->dbg_ctx), + "Failed to send drv state to MFW.\n"); + memset(&link_params, 0, sizeof(struct qed_link_params)); link_params.link_up = true; status = qed_ops->common->set_link(qedf->cdev, &link_params); @@ -3288,6 +3293,7 @@ static int qedf_probe(struct pci_dev *pdev, const struct pci_device_id *id) static void __qedf_remove(struct pci_dev *pdev, int mode) { struct qedf_ctx *qedf; + int rc; if (!pdev) { QEDF_ERR(NULL, "pdev is NULL.\n"); @@ -3382,6 +3388,12 @@ static void __qedf_remove(struct pci_dev *pdev, int mode) qed_ops->common->set_power_state(qedf->cdev, PCI_D0); pci_set_drvdata(pdev, NULL); } + + rc = qed_ops->common->update_drv_state(qedf->cdev, false); + if (rc) + QEDF_ERR(&(qedf->dbg_ctx), + "Failed to send drv state to MFW.\n"); + qed_ops->common->slowpath_stop(qedf->cdev); qed_ops->common->remove(qedf->cdev); diff --git a/drivers/scsi/qedi/qedi.h b/drivers/scsi/qedi/qedi.h index b8b22ce60ecc1d2ad626dd79732948904a2a758f..95141066c3fa813750989420676a44abe4cd4433 100644 --- a/drivers/scsi/qedi/qedi.h +++ b/drivers/scsi/qedi/qedi.h @@ -77,6 +77,11 @@ enum qedi_nvm_tgts { QEDI_NVM_TGT_SEC, }; +struct qedi_nvm_iscsi_image { + struct nvm_iscsi_cfg iscsi_cfg; + u32 crc; +}; + struct qedi_uio_ctrl { /* meta data */ u32 uio_hsi_version; @@ -294,7 +299,7 @@ struct qedi_ctx { void *bdq_pbl_list; dma_addr_t bdq_pbl_list_dma; u8 bdq_pbl_list_num_entries; - struct nvm_iscsi_cfg *iscsi_cfg; + struct qedi_nvm_iscsi_image *iscsi_image; dma_addr_t nvm_buf_dma; void __iomem *bdq_primary_prod; void __iomem *bdq_secondary_prod; diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c index 1573749fe615cb5941db790e3668759c40fec2ae..24b945b555ba3825ec4ef59c2b0fb7e7abab24fc 100644 --- a/drivers/scsi/qedi/qedi_main.c +++ b/drivers/scsi/qedi/qedi_main.c @@ -1147,23 +1147,26 @@ static int qedi_setup_int(struct qedi_ctx *qedi) static void qedi_free_nvm_iscsi_cfg(struct qedi_ctx *qedi) { - if (qedi->iscsi_cfg) + if (qedi->iscsi_image) dma_free_coherent(&qedi->pdev->dev, - sizeof(struct nvm_iscsi_cfg), - qedi->iscsi_cfg, qedi->nvm_buf_dma); + sizeof(struct qedi_nvm_iscsi_image), + qedi->iscsi_image, qedi->nvm_buf_dma); } static int qedi_alloc_nvm_iscsi_cfg(struct qedi_ctx *qedi) { - qedi->iscsi_cfg = dma_zalloc_coherent(&qedi->pdev->dev, - sizeof(struct nvm_iscsi_cfg), - &qedi->nvm_buf_dma, GFP_KERNEL); - if (!qedi->iscsi_cfg) { + struct qedi_nvm_iscsi_image nvm_image; + + qedi->iscsi_image = dma_zalloc_coherent(&qedi->pdev->dev, + sizeof(nvm_image), + &qedi->nvm_buf_dma, + GFP_KERNEL); + if (!qedi->iscsi_image) { QEDI_ERR(&qedi->dbg_ctx, "Could not allocate NVM BUF.\n"); return -ENOMEM; } QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, - "NVM BUF addr=0x%p dma=0x%llx.\n", qedi->iscsi_cfg, + "NVM BUF addr=0x%p dma=0x%llx.\n", qedi->iscsi_image, qedi->nvm_buf_dma); return 0; @@ -1716,7 +1719,7 @@ qedi_get_nvram_block(struct qedi_ctx *qedi) struct nvm_iscsi_block *block; pf = qedi->dev_info.common.abs_pf_id; - block = &qedi->iscsi_cfg->block[0]; + block = &qedi->iscsi_image->iscsi_cfg.block[0]; for (i = 0; i < NUM_OF_ISCSI_PF_SUPPORTED; i++, block++) { flags = ((block->id) & NVM_ISCSI_CFG_BLK_CTRL_FLAG_MASK) >> NVM_ISCSI_CFG_BLK_CTRL_FLAG_OFFSET; @@ -2008,15 +2011,14 @@ static void qedi_boot_release(void *data) static int qedi_get_boot_info(struct qedi_ctx *qedi) { int ret = 1; - u16 len; - - len = sizeof(struct nvm_iscsi_cfg); + struct qedi_nvm_iscsi_image nvm_image; QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, "Get NVM iSCSI CFG image\n"); ret = qedi_ops->common->nvm_get_image(qedi->cdev, QED_NVM_IMAGE_ISCSI_CFG, - (char *)qedi->iscsi_cfg, len); + (char *)qedi->iscsi_image, + sizeof(nvm_image)); if (ret) QEDI_ERR(&qedi->dbg_ctx, "Could not get NVM image. ret = %d\n", ret); @@ -2087,6 +2089,7 @@ static int qedi_setup_boot_info(struct qedi_ctx *qedi) static void __qedi_remove(struct pci_dev *pdev, int mode) { struct qedi_ctx *qedi = pci_get_drvdata(pdev); + int rval; if (qedi->tmf_thread) { flush_workqueue(qedi->tmf_thread); @@ -2116,6 +2119,10 @@ static void __qedi_remove(struct pci_dev *pdev, int mode) if (mode == QEDI_MODE_NORMAL) qedi_free_iscsi_pf_param(qedi); + rval = qedi_ops->common->update_drv_state(qedi->cdev, false); + if (rval) + QEDI_ERR(&qedi->dbg_ctx, "Failed to send drv state to MFW\n"); + if (!test_bit(QEDI_IN_OFFLINE, &qedi->flags)) { qedi_ops->common->slowpath_stop(qedi->cdev); qedi_ops->common->remove(qedi->cdev); @@ -2390,6 +2397,12 @@ static int __qedi_probe(struct pci_dev *pdev, int mode) if (qedi_setup_boot_info(qedi)) QEDI_ERR(&qedi->dbg_ctx, "No iSCSI boot target configured\n"); + + rc = qedi_ops->common->update_drv_state(qedi->cdev, true); + if (rc) + QEDI_ERR(&qedi->dbg_ctx, + "Failed to send drv state to MFW\n"); + } return 0; diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 63bea6a65d51a11d81783ee61994da758b352b86..8d579bf0fc81b5d283aabfd69ac254ace9a68a51 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -2128,34 +2128,11 @@ __qla2x00_alloc_iocbs(struct qla_qpair *qpair, srb_t *sp) req_cnt = 1; handle = 0; - if (!sp) - goto skip_cmd_array; - - /* Check for room in outstanding command list. */ - handle = req->current_outstanding_cmd; - for (index = 1; index < req->num_outstanding_cmds; index++) { - handle++; - if (handle == req->num_outstanding_cmds) - handle = 1; - if (!req->outstanding_cmds[handle]) - break; - } - if (index == req->num_outstanding_cmds) { - ql_log(ql_log_warn, vha, 0x700b, - "No room on outstanding cmd array.\n"); - goto queuing_error; - } - - /* Prep command array. */ - req->current_outstanding_cmd = handle; - req->outstanding_cmds[handle] = sp; - sp->handle = handle; - - /* Adjust entry-counts as needed. */ - if (sp->type != SRB_SCSI_CMD) + if (sp && (sp->type != SRB_SCSI_CMD)) { + /* Adjust entry-counts as needed. */ req_cnt = sp->iocbs; + } -skip_cmd_array: /* Check for room on request queue. */ if (req->cnt < req_cnt + 2) { if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha)) @@ -2179,6 +2156,28 @@ __qla2x00_alloc_iocbs(struct qla_qpair *qpair, srb_t *sp) if (req->cnt < req_cnt + 2) goto queuing_error; + if (sp) { + /* Check for room in outstanding command list. */ + handle = req->current_outstanding_cmd; + for (index = 1; index < req->num_outstanding_cmds; index++) { + handle++; + if (handle == req->num_outstanding_cmds) + handle = 1; + if (!req->outstanding_cmds[handle]) + break; + } + if (index == req->num_outstanding_cmds) { + ql_log(ql_log_warn, vha, 0x700b, + "No room on outstanding cmd array.\n"); + goto queuing_error; + } + + /* Prep command array. */ + req->current_outstanding_cmd = handle; + req->outstanding_cmds[handle] = sp; + sp->handle = handle; + } + /* Prep packet */ req->cnt -= req_cnt; pkt = req->ring_ptr; @@ -2191,6 +2190,8 @@ __qla2x00_alloc_iocbs(struct qla_qpair *qpair, srb_t *sp) pkt->handle = handle; } + return pkt; + queuing_error: qpair->tgt_counters.num_alloc_iocb_failed++; return pkt; diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 0773c6ee2428573498beeb6a746803782f72ab49..761e8b5669b05d530ed0a7a6f2858c11ad8eca7e 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -721,8 +721,24 @@ static ssize_t sdev_store_delete(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - if (device_remove_file_self(dev, attr)) - scsi_remove_device(to_scsi_device(dev)); + struct kernfs_node *kn; + + kn = sysfs_break_active_protection(&dev->kobj, &attr->attr); + WARN_ON_ONCE(!kn); + /* + * Concurrent writes into the "delete" sysfs attribute may trigger + * concurrent calls to device_remove_file() and scsi_remove_device(). + * device_remove_file() handles concurrent removal calls by + * serializing these and by ignoring the second and later removal + * attempts. Concurrent calls of scsi_remove_device() are + * serialized. The second and later calls of scsi_remove_device() are + * ignored because the first call of that function changes the device + * state into SDEV_DEL. + */ + device_remove_file(dev, attr); + scsi_remove_device(to_scsi_device(dev)); + if (kn) + sysfs_unbreak_active_protection(kn); return count; }; static DEVICE_ATTR(delete, S_IWUSR, NULL, sdev_store_delete); diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 3f3cb72e0c0cdab6a76ea8c4057229f76924899c..d0389b20574d0f778e2bfd95b07e80458970dbd5 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -523,18 +523,26 @@ static int sr_init_command(struct scsi_cmnd *SCpnt) static int sr_block_open(struct block_device *bdev, fmode_t mode) { struct scsi_cd *cd; + struct scsi_device *sdev; int ret = -ENXIO; + cd = scsi_cd_get(bdev->bd_disk); + if (!cd) + goto out; + + sdev = cd->device; + scsi_autopm_get_device(sdev); check_disk_change(bdev); mutex_lock(&sr_mutex); - cd = scsi_cd_get(bdev->bd_disk); - if (cd) { - ret = cdrom_open(&cd->cdi, bdev, mode); - if (ret) - scsi_cd_put(cd); - } + ret = cdrom_open(&cd->cdi, bdev, mode); mutex_unlock(&sr_mutex); + + scsi_autopm_put_device(sdev); + if (ret) + scsi_cd_put(cd); + +out: return ret; } @@ -562,6 +570,8 @@ static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, if (ret) goto out; + scsi_autopm_get_device(sdev); + /* * Send SCSI addressing ioctls directly to mid level, send other * ioctls to cdrom/block level. @@ -570,15 +580,18 @@ static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, case SCSI_IOCTL_GET_IDLUN: case SCSI_IOCTL_GET_BUS_NUMBER: ret = scsi_ioctl(sdev, cmd, argp); - goto out; + goto put; } ret = cdrom_ioctl(&cd->cdi, bdev, mode, cmd, arg); if (ret != -ENOSYS) - goto out; + goto put; ret = scsi_ioctl(sdev, cmd, argp); +put: + scsi_autopm_put_device(sdev); + out: mutex_unlock(&sr_mutex); return ret; diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 15e0eb99bdacf85ae7ef6ca3e7410cafc4539614..f67ff8b4e108b257e85e2d61f31e185ee4220f93 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -940,6 +940,7 @@ static int ufs_qcom_crypto_req_setup(struct ufs_hba *hba, /* Use request LBA or given dun as the DUN value */ if (req->bio) { +#ifdef CONFIG_PFK if (bio_dun(req->bio)) { /* dun @bio can be split, so we have to adjust offset */ *dun = bio_dun(req->bio); @@ -947,8 +948,11 @@ static int ufs_qcom_crypto_req_setup(struct ufs_hba *hba, *dun = req->bio->bi_iter.bi_sector; *dun >>= UFS_QCOM_ICE_TR_DATA_UNIT_4_KB; } +#else + *dun = req->bio->bi_iter.bi_sector; + *dun >>= UFS_QCOM_ICE_TR_DATA_UNIT_4_KB; +#endif } - ret = ufs_qcom_ice_req_setup(host, lrbp->cmd, cc_index, enable); return ret; @@ -1343,11 +1347,11 @@ static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_qcom_host *host, bool enable) /* * If we are here to disable this clock it might be immediately * after entering into hibern8 in which case we need to make - * sure that device ref_clk is active at least 1us after the - * hibern8 enter. + * sure that device ref_clk is active for a given time after the + * hibern8 enter for pre UFS3.0 devices */ if (!enable) - udelay(1); + udelay(host->hba->dev_ref_clk_gating_wait); writel_relaxed(temp, host->dev_ref_clk_ctrl_mmio); diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index 7ab94b585b85ff672f997d8bed5d5b03fa1e4b4c..02840d6e739b07791bcd8e31c5c4a9878dc9258e 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -504,6 +504,7 @@ struct ufs_dev_info { u8 b_device_sub_class; u16 w_manufacturer_id; u8 i_product_name; + u16 w_spec_version; /* query flags */ bool f_power_on_wp_en; @@ -527,6 +528,7 @@ struct ufs_dev_info { struct ufs_dev_desc { u16 wmanufacturerid; char model[MAX_MODEL_LEN + 1]; + u16 wspecversion; }; #endif /* End of Header */ diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 603829048be5abf67a1bd9d11e7d6ecef6fc7e19..af90101de8946ce526710025d3eb296547ea8836 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -244,6 +244,9 @@ static void ufshcd_update_uic_error_cnt(struct ufs_hba *hba, u32 reg, int type) /* default value of auto suspend is 3 seconds */ #define UFSHCD_AUTO_SUSPEND_DELAY_MS 3000 /* millisecs */ +/* default value of ref clock gating wait time is 100 micro seconds */ +#define UFSHCD_REF_CLK_GATING_WAIT_US 100 /* microsecs */ + #define UFSHCD_CLK_GATING_DELAY_MS_PWR_SAVE 10 #define UFSHCD_CLK_GATING_DELAY_MS_PERF 50 @@ -7895,7 +7898,8 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba) * to recover after multiple retries. */ if (err && ufshcd_is_embedded_dev(hba)) - WARN_ON(1); + BUG(); + /* * After reset the door-bell might be cleared, complete * outstanding requests in s/w here. @@ -8228,6 +8232,9 @@ static int ufs_get_device_desc(struct ufs_hba *hba, /* Null terminate the model string */ dev_desc->model[MAX_MODEL_LEN] = '\0'; + dev_desc->wspecversion = desc_buf[DEVICE_DESC_PARAM_SPEC_VER] << 8 | + desc_buf[DEVICE_DESC_PARAM_SPEC_VER + 1]; + out: return err; } @@ -8550,6 +8557,32 @@ static int ufshcd_set_dev_ref_clk(struct ufs_hba *hba) return err; } +static int ufshcd_get_dev_ref_clk_gating_wait(struct ufs_hba *hba, + struct ufs_dev_desc *dev_desc) +{ + int err = 0; + u32 gating_wait = UFSHCD_REF_CLK_GATING_WAIT_US; + + if (dev_desc->wspecversion >= 0x300) { + err = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR, + QUERY_ATTR_IDN_REF_CLK_GATING_WAIT_TIME, 0, 0, + &gating_wait); + + if (err) + dev_err(hba->dev, "failed reading bRefClkGatingWait. err = %d, use default %uus\n", + err, gating_wait); + + if (gating_wait == 0) { + gating_wait = UFSHCD_REF_CLK_GATING_WAIT_US; + dev_err(hba->dev, "undefined ref clk gating wait time, use default %uus\n", + gating_wait); + } + } + + hba->dev_ref_clk_gating_wait = gating_wait; + return err; +} + static int ufs_read_device_desc_data(struct ufs_hba *hba) { int err; @@ -8578,6 +8611,9 @@ static int ufs_read_device_desc_data(struct ufs_hba *hba) hba->dev_info.b_device_sub_class = desc_buf[DEVICE_DESC_PARAM_DEVICE_SUB_CLASS]; hba->dev_info.i_product_name = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; + hba->dev_info.w_spec_version = + desc_buf[DEVICE_DESC_PARAM_SPEC_VER] << 8 | + desc_buf[DEVICE_DESC_PARAM_SPEC_VER + 1]; return 0; } @@ -8651,6 +8687,8 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) "%s: Failed getting max supported power mode\n", __func__); } else { + ufshcd_get_dev_ref_clk_gating_wait(hba, &card); + /* * Set the right value to bRefClkFreq before attempting to * switch to HS gears. diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index af79660f8889888effd55869156643996efc9e7a..4fb4f57fdeb37bab44dc47a9ec19b499589dfe77 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -814,6 +814,7 @@ struct ufs_hba { unsigned int irq; bool is_irq_enabled; + u32 dev_ref_clk_gating_wait; u32 dev_ref_clk_freq; /* Interrupt aggregation support is broken */ diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index 7c28e8d4955a965805cdde3d2ddb07a7f8c5d6ea..54e3a0f6844c4c81692fe9aaa568efe1f2215866 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -91,9 +91,6 @@ struct virtio_scsi_vq { struct virtio_scsi_target_state { seqcount_t tgt_seq; - /* Count of outstanding requests. */ - atomic_t reqs; - /* Currently active virtqueue for requests sent to this target. */ struct virtio_scsi_vq *req_vq; }; @@ -152,8 +149,6 @@ static void virtscsi_complete_cmd(struct virtio_scsi *vscsi, void *buf) struct virtio_scsi_cmd *cmd = buf; struct scsi_cmnd *sc = cmd->sc; struct virtio_scsi_cmd_resp *resp = &cmd->resp.cmd; - struct virtio_scsi_target_state *tgt = - scsi_target(sc->device)->hostdata; dev_dbg(&sc->device->sdev_gendev, "cmd %p response %u status %#02x sense_len %u\n", @@ -210,8 +205,6 @@ static void virtscsi_complete_cmd(struct virtio_scsi *vscsi, void *buf) } sc->scsi_done(sc); - - atomic_dec(&tgt->reqs); } static void virtscsi_vq_done(struct virtio_scsi *vscsi, @@ -580,10 +573,7 @@ static int virtscsi_queuecommand_single(struct Scsi_Host *sh, struct scsi_cmnd *sc) { struct virtio_scsi *vscsi = shost_priv(sh); - struct virtio_scsi_target_state *tgt = - scsi_target(sc->device)->hostdata; - atomic_inc(&tgt->reqs); return virtscsi_queuecommand(vscsi, &vscsi->req_vqs[0], sc); } @@ -596,55 +586,11 @@ static struct virtio_scsi_vq *virtscsi_pick_vq_mq(struct virtio_scsi *vscsi, return &vscsi->req_vqs[hwq]; } -static struct virtio_scsi_vq *virtscsi_pick_vq(struct virtio_scsi *vscsi, - struct virtio_scsi_target_state *tgt) -{ - struct virtio_scsi_vq *vq; - unsigned long flags; - u32 queue_num; - - local_irq_save(flags); - if (atomic_inc_return(&tgt->reqs) > 1) { - unsigned long seq; - - do { - seq = read_seqcount_begin(&tgt->tgt_seq); - vq = tgt->req_vq; - } while (read_seqcount_retry(&tgt->tgt_seq, seq)); - } else { - /* no writes can be concurrent because of atomic_t */ - write_seqcount_begin(&tgt->tgt_seq); - - /* keep previous req_vq if a reader just arrived */ - if (unlikely(atomic_read(&tgt->reqs) > 1)) { - vq = tgt->req_vq; - goto unlock; - } - - queue_num = smp_processor_id(); - while (unlikely(queue_num >= vscsi->num_queues)) - queue_num -= vscsi->num_queues; - tgt->req_vq = vq = &vscsi->req_vqs[queue_num]; - unlock: - write_seqcount_end(&tgt->tgt_seq); - } - local_irq_restore(flags); - - return vq; -} - static int virtscsi_queuecommand_multi(struct Scsi_Host *sh, struct scsi_cmnd *sc) { struct virtio_scsi *vscsi = shost_priv(sh); - struct virtio_scsi_target_state *tgt = - scsi_target(sc->device)->hostdata; - struct virtio_scsi_vq *req_vq; - - if (shost_use_blk_mq(sh)) - req_vq = virtscsi_pick_vq_mq(vscsi, sc); - else - req_vq = virtscsi_pick_vq(vscsi, tgt); + struct virtio_scsi_vq *req_vq = virtscsi_pick_vq_mq(vscsi, sc); return virtscsi_queuecommand(vscsi, req_vq, sc); } @@ -775,7 +721,6 @@ static int virtscsi_target_alloc(struct scsi_target *starget) return -ENOMEM; seqcount_init(&tgt->tgt_seq); - atomic_set(&tgt->reqs, 0); tgt->req_vq = &vscsi->req_vqs[0]; starget->hostdata = tgt; @@ -823,6 +768,7 @@ static struct scsi_host_template virtscsi_host_template_single = { .target_alloc = virtscsi_target_alloc, .target_destroy = virtscsi_target_destroy, .track_queue_depth = 1, + .force_blk_mq = 1, }; static struct scsi_host_template virtscsi_host_template_multi = { @@ -844,6 +790,7 @@ static struct scsi_host_template virtscsi_host_template_multi = { .target_destroy = virtscsi_target_destroy, .map_queues = virtscsi_map_queues, .track_queue_depth = 1, + .force_blk_mq = 1, }; #define virtscsi_config_get(vdev, fld) \ diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c index 777e5f1e52d10968d5f23e0e316db05b8209511d..0cd947f78b5bfdfa013ce4909afdc8f894b6146b 100644 --- a/drivers/scsi/vmw_pvscsi.c +++ b/drivers/scsi/vmw_pvscsi.c @@ -561,9 +561,14 @@ static void pvscsi_complete_request(struct pvscsi_adapter *adapter, (btstat == BTSTAT_SUCCESS || btstat == BTSTAT_LINKED_COMMAND_COMPLETED || btstat == BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG)) { - cmd->result = (DID_OK << 16) | sdstat; - if (sdstat == SAM_STAT_CHECK_CONDITION && cmd->sense_buffer) - cmd->result |= (DRIVER_SENSE << 24); + if (sdstat == SAM_STAT_COMMAND_TERMINATED) { + cmd->result = (DID_RESET << 16); + } else { + cmd->result = (DID_OK << 16) | sdstat; + if (sdstat == SAM_STAT_CHECK_CONDITION && + cmd->sense_buffer) + cmd->result |= (DRIVER_SENSE << 24); + } } else switch (btstat) { case BTSTAT_SUCCESS: diff --git a/drivers/scsi/xen-scsifront.c b/drivers/scsi/xen-scsifront.c index 36f59a1be7e9a60be61c2b1ba8f7468dfbd8c6c9..61389bdc7926690100fc0a38fc59e8b6a73853ab 100644 --- a/drivers/scsi/xen-scsifront.c +++ b/drivers/scsi/xen-scsifront.c @@ -654,10 +654,17 @@ static int scsifront_dev_reset_handler(struct scsi_cmnd *sc) static int scsifront_sdev_configure(struct scsi_device *sdev) { struct vscsifrnt_info *info = shost_priv(sdev->host); + int err; - if (info && current == info->curr) - xenbus_printf(XBT_NIL, info->dev->nodename, + if (info && current == info->curr) { + err = xenbus_printf(XBT_NIL, info->dev->nodename, info->dev_state_path, "%d", XenbusStateConnected); + if (err) { + xenbus_dev_error(info->dev, err, + "%s: writing dev_state_path", __func__); + return err; + } + } return 0; } @@ -665,10 +672,15 @@ static int scsifront_sdev_configure(struct scsi_device *sdev) static void scsifront_sdev_destroy(struct scsi_device *sdev) { struct vscsifrnt_info *info = shost_priv(sdev->host); + int err; - if (info && current == info->curr) - xenbus_printf(XBT_NIL, info->dev->nodename, + if (info && current == info->curr) { + err = xenbus_printf(XBT_NIL, info->dev->nodename, info->dev_state_path, "%d", XenbusStateClosed); + if (err) + xenbus_dev_error(info->dev, err, + "%s: writing dev_state_path", __func__); + } } static struct scsi_host_template scsifront_sht = { @@ -1003,9 +1015,12 @@ static void scsifront_do_lun_hotplug(struct vscsifrnt_info *info, int op) if (scsi_add_device(info->host, chn, tgt, lun)) { dev_err(&dev->dev, "scsi_add_device\n"); - xenbus_printf(XBT_NIL, dev->nodename, + err = xenbus_printf(XBT_NIL, dev->nodename, info->dev_state_path, "%d", XenbusStateClosed); + if (err) + xenbus_dev_error(dev, err, + "%s: writing dev_state_path", __func__); } break; case VSCSIFRONT_OP_DEL_LUN: @@ -1019,10 +1034,14 @@ static void scsifront_do_lun_hotplug(struct vscsifrnt_info *info, int op) } break; case VSCSIFRONT_OP_READD_LUN: - if (device_state == XenbusStateConnected) - xenbus_printf(XBT_NIL, dev->nodename, + if (device_state == XenbusStateConnected) { + err = xenbus_printf(XBT_NIL, dev->nodename, info->dev_state_path, "%d", XenbusStateConnected); + if (err) + xenbus_dev_error(dev, err, + "%s: writing dev_state_path", __func__); + } break; default: break; diff --git a/drivers/soc/imx/gpc.c b/drivers/soc/imx/gpc.c index 1613ccf0c0591921bd044151fb9da9778f700023..c54d229f8da49c82f1fc9e104c2003bbe019104f 100644 --- a/drivers/soc/imx/gpc.c +++ b/drivers/soc/imx/gpc.c @@ -27,9 +27,16 @@ #define GPC_PGC_SW2ISO_SHIFT 0x8 #define GPC_PGC_SW_SHIFT 0x0 +#define GPC_PGC_PCI_PDN 0x200 +#define GPC_PGC_PCI_SR 0x20c + #define GPC_PGC_GPU_PDN 0x260 #define GPC_PGC_GPU_PUPSCR 0x264 #define GPC_PGC_GPU_PDNSCR 0x268 +#define GPC_PGC_GPU_SR 0x26c + +#define GPC_PGC_DISP_PDN 0x240 +#define GPC_PGC_DISP_SR 0x24c #define GPU_VPU_PUP_REQ BIT(1) #define GPU_VPU_PDN_REQ BIT(0) @@ -303,10 +310,24 @@ static const struct of_device_id imx_gpc_dt_ids[] = { { } }; +static const struct regmap_range yes_ranges[] = { + regmap_reg_range(GPC_CNTR, GPC_CNTR), + regmap_reg_range(GPC_PGC_PCI_PDN, GPC_PGC_PCI_SR), + regmap_reg_range(GPC_PGC_GPU_PDN, GPC_PGC_GPU_SR), + regmap_reg_range(GPC_PGC_DISP_PDN, GPC_PGC_DISP_SR), +}; + +static const struct regmap_access_table access_table = { + .yes_ranges = yes_ranges, + .n_yes_ranges = ARRAY_SIZE(yes_ranges), +}; + static const struct regmap_config imx_gpc_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, + .rd_table = &access_table, + .wr_table = &access_table, .max_register = 0x2ac, }; diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c index f4e3bd40c72e60c0448c98456f7b53f6be7936bd..6ef18cf8f24387e324cf455ae98c30f2b27c95d3 100644 --- a/drivers/soc/imx/gpcv2.c +++ b/drivers/soc/imx/gpcv2.c @@ -39,10 +39,15 @@ #define GPC_M4_PU_PDN_FLG 0x1bc - -#define PGC_MIPI 4 -#define PGC_PCIE 5 -#define PGC_USB_HSIC 8 +/* + * The PGC offset values in Reference Manual + * (Rev. 1, 01/2018 and the older ones) GPC chapter's + * GPC_PGC memory map are incorrect, below offset + * values are from design RTL. + */ +#define PGC_MIPI 16 +#define PGC_PCIE 17 +#define PGC_USB_HSIC 20 #define GPC_PGC_CTRL(n) (0x800 + (n) * 0x40) #define GPC_PGC_SR(n) (GPC_PGC_CTRL(n) + 0xc) diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 314a163faa262e2dfa96a4c844145f05f00936b0..eb3ed076ccbc819ab57b2a1b8b8defb7aaeeb31e 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -277,6 +277,7 @@ config QCOM_SMEM_STATE config QCOM_SMP2P tristate "Qualcomm Shared Memory Point to Point support" + depends on MAILBOX depends on QCOM_SMEM select QCOM_SMEM_STATE help @@ -833,4 +834,11 @@ config QCOM_CX_IPEAK bit in tcsr register if it is going to cross its own threshold. If all clients are going to cross their thresholds then Cx ipeak hw module will raise an interrupt to cDSP block to throttle cDSP fmax. + +config QCOM_AOP_DDR_MESSAGING + bool "Send messages to AOP about the DDR frequency during reboot" + help + This driver sends messages to the AOP to adjust the DDR frequency when + the device is rebooting, to ensure that the device is powered off + cleanly. endmenu diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 05febcc529e757a7e1df4efdaff13252a4469fbd..c7f741fbf9137642c054b81fe915a50d524ed233 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -93,3 +93,4 @@ obj-$(CONFIG_QCOM_SMP2P_SLEEPSTATE) += smp2p_sleepstate.o obj-$(CONFIG_QCOM_MEM_OFFLINE) += mem-offline.o obj-$(CONFIG_QCOM_CDSP_RM) += cdsprm.o obj-$(CONFIG_QCOM_CX_IPEAK) += cx_ipeak.o +obj-$(CONFIG_QCOM_AOP_DDR_MESSAGING) += aop_ddr_msgs.o diff --git a/drivers/soc/qcom/aop_ddr_msgs.c b/drivers/soc/qcom/aop_ddr_msgs.c new file mode 100644 index 0000000000000000000000000000000000000000..b7be6974fb16ce909d6282d532a0a2db60773d0b --- /dev/null +++ b/drivers/soc/qcom/aop_ddr_msgs.c @@ -0,0 +1,123 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_AOP_MSG_LEN 96 +#define AOP_DDR_TARG_FREQ_MHZ 300 + +struct mbox_data { + struct mbox_client cl; + struct mbox_chan *mbox; + struct notifier_block reboot_notif_blk; +}; + +static void send_aop_ddr_freq_msg(struct mbox_data *aop_mbox, int freq_mhz) +{ + struct qmp_pkt pkt; + char mbox_msg[MAX_AOP_MSG_LEN + 1] = {0}; + int rc; + + scnprintf(mbox_msg, MAX_AOP_MSG_LEN, + "{class: ddr, res: fixed, val: %d}", freq_mhz); + pkt.size = MAX_AOP_MSG_LEN; + pkt.data = mbox_msg; + + rc = mbox_send_message(aop_mbox->mbox, &pkt); + + if (rc < 0) + pr_err("Failed to send AOP DDR freq msg: %d rc: %d\n", freq_mhz, + rc); +} + +static int aop_ddr_freq_msg_handler(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct mbox_data *aop_mbox = container_of(this, struct mbox_data, + reboot_notif_blk); + + if (event == SYS_HALT || event == SYS_POWER_OFF) + send_aop_ddr_freq_msg(aop_mbox, AOP_DDR_TARG_FREQ_MHZ); + + return NOTIFY_DONE; +} + +static int aop_ddr_msgs_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + int rc; + struct mbox_data *aop_mbox = devm_kzalloc(dev, sizeof(*aop_mbox), + GFP_KERNEL); + + if (!aop_mbox) + return -ENOMEM; + + aop_mbox->cl.dev = dev; + aop_mbox->cl.tx_block = true; + aop_mbox->cl.tx_tout = 1000; + aop_mbox->cl.knows_txdone = false; + aop_mbox->mbox = mbox_request_channel(&aop_mbox->cl, 0); + if (IS_ERR(aop_mbox->mbox)) { + rc = PTR_ERR(aop_mbox->mbox); + pr_err("Failed to get mailbox channel rc: %d\n", rc); + return rc; + } + + aop_mbox->reboot_notif_blk.notifier_call = aop_ddr_freq_msg_handler; + platform_set_drvdata(pdev, aop_mbox); + rc = register_reboot_notifier(&aop_mbox->reboot_notif_blk); + if (rc < 0) { + pr_err("Failed to register to the reboot notifier rc: %d\n", + rc); + mbox_free_channel(aop_mbox->mbox); + platform_set_drvdata(pdev, NULL); + } + return rc; +} + +static int aop_ddr_msgs_remove(struct platform_device *pdev) +{ + struct mbox_data *aop_mbox = platform_get_drvdata(pdev); + + mbox_free_channel(aop_mbox->mbox); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static const struct of_device_id of_aop_ddr_match_tbl[] = { + { .compatible = "qcom,aop-ddr-msgs", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_aop_ddr_match_tbl); + +static struct platform_driver aop_ddr_msgs_driver = { + .probe = aop_ddr_msgs_probe, + .remove = aop_ddr_msgs_remove, + .driver = { + .name = "aop-ddr-msgs", + .of_match_table = of_match_ptr(of_aop_ddr_match_tbl), + }, +}; +module_platform_driver(aop_ddr_msgs_driver); + +MODULE_DESCRIPTION("Qualcomm Technologies Inc AOP DDR Messaging driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c index 22b44648a4029a16114d807b2f16a751de59e368..758717ca00549f8974101165585824291eb23fbb 100644 --- a/drivers/soc/qcom/cmd-db.c +++ b/drivers/soc/qcom/cmd-db.c @@ -352,6 +352,7 @@ static int cmd_db_dev_probe(struct platform_device *pdev) dict = of_iomap(pdev->dev.of_node, 0); if (!dict) { cmd_db_status = -ENOMEM; + pr_err("Command DB dictionary addr not found.\n"); goto failed; } @@ -372,6 +373,7 @@ static int cmd_db_dev_probe(struct platform_device *pdev) if (!cmd_db_header) { cmd_db_status = -ENOMEM; + pr_err("Command DB header not found.\n"); goto failed; } diff --git a/drivers/soc/qcom/dfc_qmi.c b/drivers/soc/qcom/dfc_qmi.c index 95d7443334a1b181d1d882b10f89922bfc6229f2..8c3047544c0b128ba24d3ad4c7996ba29345ba4c 100644 --- a/drivers/soc/qcom/dfc_qmi.c +++ b/drivers/soc/qcom/dfc_qmi.c @@ -58,12 +58,15 @@ struct dfc_qmi_data { struct work_struct svc_arrive; struct qmi_handle handle; struct sockaddr_qrtr ssctl; + struct svc_info svc; + struct work_struct qmi_ind_work; + struct list_head qmi_ind_q; + spinlock_t qmi_ind_lock; int index; int restart_state; }; static void dfc_svc_init(struct work_struct *work); -static void dfc_do_burst_flow_control(struct work_struct *work); /* **************************************************** */ #define DFC_SERVICE_ID_V01 0x4E @@ -307,8 +310,7 @@ struct dfc_flow_status_ind_msg_v01 { }; struct dfc_svc_ind { - struct work_struct work; - struct dfc_qmi_data *data; + struct list_head list; struct dfc_flow_status_ind_msg_v01 dfc_info; }; @@ -618,12 +620,11 @@ dfc_indication_register_req(struct qmi_handle *dfc_handle, return ret; } -static int dfc_init_service(struct dfc_qmi_data *data, struct qmi_info *qmi) +static int dfc_init_service(struct dfc_qmi_data *data) { int rc; - rc = dfc_bind_client_req(&data->handle, &data->ssctl, - &qmi->fc_info[data->index].svc); + rc = dfc_bind_client_req(&data->handle, &data->ssctl, &data->svc); if (rc < 0) return rc; @@ -674,16 +675,13 @@ static int dfc_bearer_flow_ctl(struct net_device *dev, struct rmnet_bearer_map *bearer, struct qos_info *qos) { - struct list_head *p; struct rmnet_flow_map *itm; int rc = 0, qlen; int enable; enable = bearer->grant_size ? 1 : 0; - list_for_each(p, &qos->flow_head) { - itm = list_entry(p, struct rmnet_flow_map, list); - + list_for_each_entry(itm, &qos->flow_head, list) { if (itm->bearer_id == bearer->bearer_id) { /* * Do not flow disable ancillary q if ancillary is true @@ -713,14 +711,14 @@ static int dfc_all_bearer_flow_ctl(struct net_device *dev, struct qos_info *qos, u8 ack_req, u32 ancillary, struct dfc_flow_status_info_type_v01 *fc_info) { - struct list_head *p; - struct rmnet_bearer_map *bearer_itm = NULL; - int enable; - int rc = 0; + struct rmnet_bearer_map *bearer_itm; + struct rmnet_flow_map *flow_itm; + int rc = 0, qlen; + bool enable; - list_for_each(p, &qos->bearer_head) { - bearer_itm = list_entry(p, struct rmnet_bearer_map, list); + enable = fc_info->num_bytes > 0 ? 1 : 0; + list_for_each_entry(bearer_itm, &qos->bearer_head, list) { bearer_itm->grant_size = fc_info->num_bytes; bearer_itm->grant_thresh = qmi_rmnet_grant_per(bearer_itm->grant_size); @@ -729,14 +727,14 @@ static int dfc_all_bearer_flow_ctl(struct net_device *dev, bearer_itm->ancillary = ancillary; } - enable = fc_info->num_bytes > 0 ? 1 : 0; - - if (enable) - netif_tx_wake_all_queues(dev); - else - netif_tx_stop_all_queues(dev); - - trace_dfc_qmi_tc(dev->name, 0xFF, 0, fc_info->num_bytes, 0, 0, enable); + list_for_each_entry(flow_itm, &qos->flow_head, list) { + qlen = qmi_rmnet_flow_control(dev, flow_itm->tcm_handle, + enable); + trace_dfc_qmi_tc(dev->name, flow_itm->bearer_id, + flow_itm->flow_id, fc_info->num_bytes, + qlen, flow_itm->tcm_handle, enable); + rc++; + } if (enable == 0 && ack_req) dfc_send_ack(dev, fc_info->bearer_id, @@ -776,9 +774,9 @@ static int dfc_update_fc_map(struct net_device *dev, struct qos_info *qos, return rc; } -static void dfc_do_burst_flow_control(struct work_struct *work) +static void dfc_do_burst_flow_control(struct dfc_qmi_data *dfc, + struct dfc_svc_ind *svc_ind) { - struct dfc_svc_ind *svc_ind = (struct dfc_svc_ind *)work; struct dfc_flow_status_ind_msg_v01 *ind = &svc_ind->dfc_info; struct net_device *dev; struct qos_info *qos; @@ -788,11 +786,6 @@ static void dfc_do_burst_flow_control(struct work_struct *work) u32 ancillary; int i, j; - if (unlikely(svc_ind->data->restart_state)) { - kfree(svc_ind); - return; - } - rcu_read_lock(); for (i = 0; i < ind->flow_status_len; i++) { @@ -810,7 +803,7 @@ static void dfc_do_burst_flow_control(struct work_struct *work) } } - trace_dfc_flow_ind(svc_ind->data->index, + trace_dfc_flow_ind(dfc->index, i, flow_status->mux_id, flow_status->bearer_id, flow_status->num_bytes, @@ -818,7 +811,7 @@ static void dfc_do_burst_flow_control(struct work_struct *work) ack_req, ancillary); - dev = rmnet_get_rmnet_dev(svc_ind->data->rmnet_port, + dev = rmnet_get_rmnet_dev(dfc->rmnet_port, flow_status->mux_id); if (!dev) goto clean_out; @@ -841,7 +834,36 @@ static void dfc_do_burst_flow_control(struct work_struct *work) clean_out: rcu_read_unlock(); - kfree(svc_ind); +} + +static void dfc_qmi_ind_work(struct work_struct *work) +{ + struct dfc_qmi_data *dfc = container_of(work, struct dfc_qmi_data, + qmi_ind_work); + struct dfc_svc_ind *svc_ind; + unsigned long flags; + + if (!dfc) + return; + + local_bh_disable(); + + do { + spin_lock_irqsave(&dfc->qmi_ind_lock, flags); + svc_ind = list_first_entry_or_null(&dfc->qmi_ind_q, + struct dfc_svc_ind, list); + if (svc_ind) + list_del(&svc_ind->list); + spin_unlock_irqrestore(&dfc->qmi_ind_lock, flags); + + if (svc_ind) { + if (!dfc->restart_state) + dfc_do_burst_flow_control(dfc, svc_ind); + kfree(svc_ind); + } + } while (svc_ind != NULL); + + local_bh_enable(); } static void dfc_clnt_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, @@ -851,6 +873,7 @@ static void dfc_clnt_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, handle); struct dfc_flow_status_ind_msg_v01 *ind_msg; struct dfc_svc_ind *svc_ind; + unsigned long flags; if (qmi != &dfc->handle) return; @@ -867,13 +890,13 @@ static void dfc_clnt_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, if (!svc_ind) return; - INIT_WORK((struct work_struct *)svc_ind, - dfc_do_burst_flow_control); - memcpy(&svc_ind->dfc_info, ind_msg, sizeof(*ind_msg)); - svc_ind->data = dfc; - queue_work(dfc->dfc_wq, (struct work_struct *)svc_ind); + spin_lock_irqsave(&dfc->qmi_ind_lock, flags); + list_add_tail(&svc_ind->list, &dfc->qmi_ind_q); + spin_unlock_irqrestore(&dfc->qmi_ind_lock, flags); + + queue_work(dfc->dfc_wq, &dfc->qmi_ind_work); } } @@ -884,19 +907,26 @@ static void dfc_svc_init(struct work_struct *work) svc_arrive); struct qmi_info *qmi; - qmi = (struct qmi_info *)rmnet_get_qmi_pt(data->rmnet_port); - if (!qmi) - goto clean_out; - - rc = dfc_init_service(data, qmi); + rc = dfc_init_service(data); if (rc < 0) goto clean_out; - qmi->fc_info[data->index].dfc_client = (void *)data; trace_dfc_client_state_up(data->index, - qmi->fc_info[data->index].svc.instance, - qmi->fc_info[data->index].svc.ep_type, - qmi->fc_info[data->index].svc.iface_id); + data->svc.instance, + data->svc.ep_type, + data->svc.iface_id); + + rtnl_lock(); + qmi = (struct qmi_info *)rmnet_get_qmi_pt(data->rmnet_port); + if (!qmi) { + rtnl_unlock(); + goto clean_out; + } + + qmi->dfc_clients[data->index] = (void *)data; + rtnl_unlock(); + + pr_info("Connection established with the DFC Service\n"); return; clean_out: @@ -944,7 +974,7 @@ static struct qmi_msg_handler qmi_indication_handler[] = { {}, }; -int dfc_qmi_client_init(void *port, int index, struct qmi_info *qmi) +int dfc_qmi_client_init(void *port, int index, struct svc_info *psvc) { struct dfc_qmi_data *data; int rc = -ENOMEM; @@ -956,6 +986,11 @@ int dfc_qmi_client_init(void *port, int index, struct qmi_info *qmi) data->rmnet_port = port; data->index = index; data->restart_state = 0; + memcpy(&data->svc, psvc, sizeof(data->svc)); + + INIT_WORK(&data->qmi_ind_work, dfc_qmi_ind_work); + INIT_LIST_HEAD(&data->qmi_ind_q); + spin_lock_init(&data->qmi_ind_lock); data->dfc_wq = create_singlethread_workqueue("dfc_wq"); if (!data->dfc_wq) { @@ -974,7 +1009,7 @@ int dfc_qmi_client_init(void *port, int index, struct qmi_info *qmi) rc = qmi_add_lookup(&data->handle, DFC_SERVICE_ID_V01, DFC_SERVICE_VERS_V01, - qmi->fc_info[index].svc.instance); + psvc->instance); if (rc < 0) { pr_err("%s: failed qmi_add_lookup - rc[%d]\n", __func__, rc); goto err2; @@ -1058,7 +1093,7 @@ void dfc_qmi_wq_flush(struct qmi_info *qmi) int i; for (i = 0; i < MAX_CLIENT_NUM; i++) { - dfc_data = (struct dfc_qmi_data *)(qmi->fc_info[i].dfc_client); + dfc_data = (struct dfc_qmi_data *)(qmi->dfc_clients[i]); if (dfc_data) flush_workqueue(dfc_data->dfc_wq); } diff --git a/drivers/soc/qcom/eud.c b/drivers/soc/qcom/eud.c index e88681d564abd3d7aae7d23ce8bf43511084b084..0919f07cf1ff8e296327f0ca9e9f0c611ffe947a 100644 --- a/drivers/soc/qcom/eud.c +++ b/drivers/soc/qcom/eud.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,7 @@ #include #include #include +#include #define EUD_ENABLE_CMD 1 #define EUD_DISABLE_CMD 0 @@ -37,6 +39,7 @@ #define EUD_REG_COM_RX_ID 0x000C #define EUD_REG_COM_RX_LEN 0x0010 #define EUD_REG_COM_RX_DAT 0x0014 +#define EUD_REG_EUD_EN2 0x0000 #define EUD_REG_INT1_EN_MASK 0x0024 #define EUD_REG_INT_STATUS_1 0x0044 #define EUD_REG_CTL_OUT_1 0x0074 @@ -71,6 +74,8 @@ struct eud_chip { struct uart_port port; struct work_struct eud_work; struct power_supply *batt_psy; + bool secure_eud_en; + phys_addr_t eud_mode_mgr2_phys_base; }; static const unsigned int eud_extcon_cable[] = { @@ -122,6 +127,14 @@ static void enable_eud(struct platform_device *pdev) /* Enable vbus, chgr & safe mode warning interrupts */ writel_relaxed(EUD_INT_VBUS | EUD_INT_CHGR | EUD_INT_SAFE_MODE, priv->eud_reg_base + EUD_REG_INT1_EN_MASK); + /* Enable secure eud if supported */ + if (priv->secure_eud_en) { + ret = scm_io_write(priv->eud_mode_mgr2_phys_base + + EUD_REG_EUD_EN2, EUD_ENABLE_CMD); + if (ret) + dev_err(&pdev->dev, + "scm_io_write failed with rc:%d\n", ret); + } /* Ensure Register Writes Complete */ wmb(); @@ -143,9 +156,19 @@ static void enable_eud(struct platform_device *pdev) static void disable_eud(struct platform_device *pdev) { struct eud_chip *priv = platform_get_drvdata(pdev); + int ret; /* write into CSR to disable EUD */ writel_relaxed(0, priv->eud_reg_base + EUD_REG_CSR_EUD_EN); + /* Disable secure eud if supported */ + if (priv->secure_eud_en) { + ret = scm_io_write(priv->eud_mode_mgr2_phys_base + + EUD_REG_EUD_EN2, EUD_DISABLE_CMD); + if (ret) + dev_err(&pdev->dev, + "scm_io_write failed with rc:%d\n", ret); + } + dev_dbg(&pdev->dev, "%s: EUD Disabled!\n", __func__); } @@ -523,6 +546,22 @@ static int msm_eud_probe(struct platform_device *pdev) chip->eud_irq = platform_get_irq_byname(pdev, "eud_irq"); + chip->secure_eud_en = of_property_read_bool(pdev->dev.of_node, + "qcom,secure-eud-en"); + if (chip->secure_eud_en) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "eud_mode_mgr2"); + if (!res) { + dev_err(chip->dev, + "%s: failed to get resource eud_mode_mgr2\n", + __func__); + ret = -ENOMEM; + return ret; + } + + chip->eud_mode_mgr2_phys_base = res->start; + } + ret = devm_request_irq(&pdev->dev, chip->eud_irq, handle_eud_irq, IRQF_TRIGGER_HIGH, "eud_irq", chip); if (ret) { diff --git a/drivers/soc/qcom/fsa4480-i2c.c b/drivers/soc/qcom/fsa4480-i2c.c index 8d4b37d5ec878f04a66389e52e4b2f81e86f988f..38ce573788703c73d5858407c28454c1011bee60 100644 --- a/drivers/soc/qcom/fsa4480-i2c.c +++ b/drivers/soc/qcom/fsa4480-i2c.c @@ -123,6 +123,7 @@ static int fsa4480_usbc_event_changed(struct notifier_block *nb, dev_dbg(dev, "%s: queueing usbc_analog_work\n", __func__); + pm_stay_awake(fsa_priv->dev); schedule_work(&fsa_priv->usbc_analog_work); break; default: @@ -303,6 +304,7 @@ static void fsa4480_usbc_analog_work_fn(struct work_struct *work) } fsa4480_usbc_analog_setup_switches(fsa_priv, atomic_read(&(fsa_priv->usbc_mode)) != POWER_SUPPLY_TYPEC_NONE); + pm_relax(fsa_priv->dev); } static void fsa4480_update_reg_defaults(struct regmap *regmap) @@ -387,7 +389,8 @@ static int fsa4480_remove(struct i2c_client *i2c) return -EINVAL; fsa4480_usbc_update_settings(fsa_priv, 0x18, 0x98); - + cancel_work(&fsa_priv->usbc_analog_work); + pm_relax(fsa_priv->dev); /* deregister from PMI */ power_supply_unreg_notifier(&fsa_priv->psy_nb); power_supply_put(fsa_priv->usb_psy); diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 43ed294bf180bf4b1c75eeedb6c1831c1ef51228..4e59b04cc2d9fe1937de87b33c1cfcf58358b941 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -610,7 +610,8 @@ bool icnss_is_fw_down(void) return false; return test_bit(ICNSS_FW_DOWN, &penv->state) || - test_bit(ICNSS_PD_RESTART, &penv->state); + test_bit(ICNSS_PD_RESTART, &penv->state) || + test_bit(ICNSS_REJUVENATE, &penv->state); } EXPORT_SYMBOL(icnss_is_fw_down); @@ -775,12 +776,14 @@ int icnss_call_driver_uevent(struct icnss_priv *priv, static int icnss_driver_event_server_arrive(void *data) { int ret = 0; + bool ignore_assert = false; if (!penv) return -ENODEV; set_bit(ICNSS_WLFW_EXISTS, &penv->state); clear_bit(ICNSS_FW_DOWN, &penv->state); + icnss_ignore_fw_timeout(false); ret = icnss_connect_to_fw_server(penv, data); if (ret) @@ -793,8 +796,10 @@ static int icnss_driver_event_server_arrive(void *data) goto clear_server; ret = wlfw_ind_register_send_sync_msg(penv); - if (ret < 0) + if (ret < 0) { + ignore_assert = true; goto err_power_on; + } if (!penv->msa_va) { icnss_pr_err("Invalid MSA address\n"); @@ -803,8 +808,10 @@ static int icnss_driver_event_server_arrive(void *data) } ret = wlfw_msa_mem_info_send_sync_msg(penv); - if (ret < 0) + if (ret < 0) { + ignore_assert = true; goto err_power_on; + } if (!test_bit(ICNSS_MSA0_ASSIGNED, &penv->state)) { ret = icnss_assign_msa_perm_all(penv, @@ -815,12 +822,16 @@ static int icnss_driver_event_server_arrive(void *data) } ret = wlfw_msa_ready_send_sync_msg(penv); - if (ret < 0) + if (ret < 0) { + ignore_assert = true; goto err_setup_msa; + } ret = wlfw_cap_send_sync_msg(penv); - if (ret < 0) + if (ret < 0) { + ignore_assert = true; goto err_setup_msa; + } wlfw_dynamic_feature_mask_send_sync_msg(penv, dynamic_feature_mask); @@ -841,7 +852,7 @@ static int icnss_driver_event_server_arrive(void *data) clear_server: icnss_clear_server(penv); fail: - ICNSS_ASSERT(0); + ICNSS_ASSERT(ignore_assert); return ret; } @@ -972,6 +983,7 @@ static int icnss_driver_event_fw_ready_ind(void *data) return -ENODEV; set_bit(ICNSS_FW_READY, &penv->state); + clear_bit(ICNSS_MODE_ON, &penv->state); icnss_pr_info("WLAN FW is ready: 0x%lx\n", penv->state); @@ -1090,8 +1102,13 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv, int ret = 0; struct icnss_event_pd_service_down_data *event_data = data; - if (!test_bit(ICNSS_WLFW_EXISTS, &priv->state)) + if (!test_bit(ICNSS_WLFW_EXISTS, &priv->state)) { + icnss_ignore_fw_timeout(false); goto out; + } + + if (priv->force_err_fatal) + ICNSS_ASSERT(0); if (priv->early_crash_ind) { icnss_pr_dbg("PD Down ignored as early indication is processed: %d, state: 0x%lx\n", @@ -1107,16 +1124,11 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv, goto out; } - if (priv->force_err_fatal) - ICNSS_ASSERT(0); - icnss_fw_crashed(priv, event_data); out: kfree(data); - icnss_ignore_fw_timeout(false); - return ret; } @@ -1125,15 +1137,16 @@ static int icnss_driver_event_early_crash_ind(struct icnss_priv *priv, { int ret = 0; - if (!test_bit(ICNSS_WLFW_EXISTS, &priv->state)) + if (!test_bit(ICNSS_WLFW_EXISTS, &priv->state)) { + icnss_ignore_fw_timeout(false); goto out; + } priv->early_crash_ind = true; icnss_fw_crashed(priv, NULL); out: kfree(data); - icnss_ignore_fw_timeout(false); return ret; } @@ -1767,6 +1780,8 @@ EXPORT_SYMBOL(icnss_disable_irq); int icnss_get_soc_info(struct device *dev, struct icnss_soc_info *info) { + char *fw_build_timestamp = NULL; + if (!penv || !dev) { icnss_pr_err("Platform driver not initialized\n"); return -EINVAL; @@ -1779,6 +1794,8 @@ int icnss_get_soc_info(struct device *dev, struct icnss_soc_info *info) info->board_id = penv->board_id; info->soc_id = penv->soc_id; info->fw_version = penv->fw_version_info.fw_version; + fw_build_timestamp = penv->fw_version_info.fw_build_timestamp; + fw_build_timestamp[WLFW_MAX_TIMESTAMP_LEN] = '\0'; strlcpy(info->fw_build_timestamp, penv->fw_version_info.fw_build_timestamp, WLFW_MAX_TIMESTAMP_LEN + 1); @@ -1794,7 +1811,8 @@ int icnss_set_fw_log_mode(struct device *dev, uint8_t fw_log_mode) if (!dev) return -ENODEV; - if (test_bit(ICNSS_FW_DOWN, &penv->state)) { + if (test_bit(ICNSS_FW_DOWN, &penv->state) || + !test_bit(ICNSS_FW_READY, &penv->state)) { icnss_pr_err("FW down, ignoring fw_log_mode state: 0x%lx\n", penv->state); return -EINVAL; @@ -1886,12 +1904,19 @@ int icnss_wlan_enable(struct device *dev, struct icnss_wlan_enable_cfg *config, enum icnss_driver_mode mode, const char *host_version) { - if (test_bit(ICNSS_FW_DOWN, &penv->state)) { + if (test_bit(ICNSS_FW_DOWN, &penv->state) || + !test_bit(ICNSS_FW_READY, &penv->state)) { icnss_pr_err("FW down, ignoring wlan_enable state: 0x%lx\n", penv->state); return -EINVAL; } + if (test_bit(ICNSS_MODE_ON, &penv->state)) { + icnss_pr_err("Already Mode on, ignoring wlan_enable state: 0x%lx\n", + penv->state); + return -EINVAL; + } + return icnss_send_wlan_enable_to_fw(penv, config, mode, host_version); } EXPORT_SYMBOL(icnss_wlan_enable); @@ -2064,6 +2089,7 @@ static int icnss_smmu_init(struct icnss_priv *priv) int atomic_ctx = 1; int s1_bypass = 1; int fast = 1; + int stall_disable = 1; int ret = 0; icnss_pr_dbg("Initializing SMMU\n"); @@ -2107,6 +2133,16 @@ static int icnss_smmu_init(struct icnss_priv *priv) goto set_attr_fail; } icnss_pr_dbg("SMMU FAST map set\n"); + + ret = iommu_domain_set_attr(mapping->domain, + DOMAIN_ATTR_CB_STALL_DISABLE, + &stall_disable); + if (ret < 0) { + icnss_pr_err("Set stall disable map attribute failed, err = %d\n", + ret); + goto set_attr_fail; + } + icnss_pr_dbg("SMMU STALL DISABLE map set\n"); } ret = arm_iommu_attach_device(&priv->pdev->dev, mapping); @@ -2534,6 +2570,9 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv) continue; case ICNSS_REJUVENATE: seq_puts(s, "FW REJUVENATE"); + continue; + case ICNSS_MODE_ON: + seq_puts(s, "MODE ON DONE"); } seq_printf(s, "UNKNOWN-%d", i); diff --git a/drivers/soc/qcom/icnss_private.h b/drivers/soc/qcom/icnss_private.h index 7fc3c9cbf9f076024d2f3efa5216cbf9248dc0f1..4d524e7f4197a2459e10ffcaa156d22554f80617 100644 --- a/drivers/soc/qcom/icnss_private.h +++ b/drivers/soc/qcom/icnss_private.h @@ -155,6 +155,7 @@ enum icnss_driver_state { ICNSS_FW_DOWN, ICNSS_DRIVER_UNLOADING, ICNSS_REJUVENATE, + ICNSS_MODE_ON, }; struct ce_irq_list { diff --git a/drivers/soc/qcom/icnss_qmi.c b/drivers/soc/qcom/icnss_qmi.c index 0aefbe99ddcff223707694fcc9cfe14340c86e79..8d391c47fa2b3722398674f344a5f55b8bb2cff3 100644 --- a/drivers/soc/qcom/icnss_qmi.c +++ b/drivers/soc/qcom/icnss_qmi.c @@ -471,6 +471,16 @@ int wlfw_wlan_mode_send_sync_msg(struct icnss_priv *priv, priv->stats.mode_resp++; + if (mode == QMI_WLFW_OFF_V01) { + icnss_pr_dbg("Clear mode on 0x%lx, mode: %d\n", + priv->state, mode); + clear_bit(ICNSS_MODE_ON, &priv->state); + } else { + icnss_pr_dbg("Set mode on 0x%lx, mode: %d\n", + priv->state, mode); + set_bit(ICNSS_MODE_ON, &priv->state); + } + kfree(resp); kfree(req); return 0; diff --git a/drivers/soc/qcom/mem-offline.c b/drivers/soc/qcom/mem-offline.c index dbd16078134237ca2c3f53a8a90c150697c207be..b01f80f05ecd344699132965c78c70c9c1430568 100644 --- a/drivers/soc/qcom/mem-offline.c +++ b/drivers/soc/qcom/mem-offline.c @@ -126,6 +126,14 @@ static int mem_event_callback(struct notifier_block *self, start_addr = __pfn_to_phys(start); end_addr = __pfn_to_phys(end); sec_nr = pfn_to_section_nr(start); + + if (sec_nr > end_section_nr || sec_nr < start_section_nr) { + if (action == MEM_ONLINE || action == MEM_OFFLINE) + pr_info("mem-offline: %s mem%d, but not our block. Not performing any action\n", + action == MEM_ONLINE ? "Onlined" : "Offlined", + sec_nr); + return NOTIFY_OK; + } switch (action) { case MEM_GOING_ONLINE: pr_debug("mem-offline: MEM_GOING_ONLINE : start = 0x%lx end = 0x%lx", diff --git a/drivers/soc/qcom/qmi_interface.c b/drivers/soc/qcom/qmi_interface.c index 44c035fbe06982557021291ae46d9510e45c8f7b..d4c5e8e863273253c9d908f68bc947fa2dc99648 100644 --- a/drivers/soc/qcom/qmi_interface.c +++ b/drivers/soc/qcom/qmi_interface.c @@ -353,6 +353,9 @@ int qmi_txn_wait(struct qmi_txn *txn, unsigned long timeout) ret = wait_for_completion_timeout(&txn->completion, timeout); + if (txn->result == -ENETRESET) + return txn->result; + mutex_lock(&qmi->txn_lock); mutex_lock(&txn->lock); idr_remove(&qmi->txns, txn->id); @@ -605,6 +608,7 @@ static struct socket *qmi_sock_create(struct qmi_handle *qmi, sock->sk->sk_user_data = qmi; sock->sk->sk_data_ready = qmi_data_ready; sock->sk->sk_error_report = qmi_data_ready; + sock->sk->sk_sndtimeo = HZ * 10; return sock; } @@ -684,6 +688,8 @@ void qmi_handle_release(struct qmi_handle *qmi) { struct socket *sock = qmi->sock; struct qmi_service *svc, *tmp; + struct qmi_txn *txn; + int txn_id; sock->sk->sk_user_data = NULL; cancel_work_sync(&qmi->work); @@ -697,6 +703,12 @@ void qmi_handle_release(struct qmi_handle *qmi) destroy_workqueue(qmi->wq); + mutex_lock(&qmi->txn_lock); + idr_for_each_entry(&qmi->txns, txn, txn_id) { + txn->result = -ENETRESET; + complete(&txn->completion); + } + mutex_unlock(&qmi->txn_lock); idr_destroy(&qmi->txns); kfree(qmi->recv_buf); diff --git a/drivers/soc/qcom/qmi_rmnet.c b/drivers/soc/qcom/qmi_rmnet.c index d1c4eb7992d50810b4ff662bce5399ed1a30dfcb..e3996137d6a7c26a3e6d60879c0b2d82ec730217 100644 --- a/drivers/soc/qcom/qmi_rmnet.c +++ b/drivers/soc/qcom/qmi_rmnet.c @@ -33,12 +33,13 @@ #define FLAG_POWERSAVE_MASK 0x0010 #define DFC_MODE_MULTIQ 2 -unsigned int rmnet_wq_frequency __read_mostly = 4; +unsigned int rmnet_wq_frequency __read_mostly = 1000; module_param(rmnet_wq_frequency, uint, 0644); -MODULE_PARM_DESC(rmnet_wq_frequency, "Frequency of PS check"); +MODULE_PARM_DESC(rmnet_wq_frequency, "Frequency of PS check in ms"); #define PS_WORK_ACTIVE_BIT 0 -#define PS_INTERVAL (((!rmnet_wq_frequency) ? 1 : rmnet_wq_frequency) * HZ) +#define PS_INTERVAL (((!rmnet_wq_frequency) ? \ + 1 : rmnet_wq_frequency/10) * (HZ/100)) #define NO_DELAY (0x0000 * HZ) #ifdef CONFIG_QCOM_QMI_DFC @@ -86,8 +87,8 @@ void *qmi_rmnet_has_dfc_client(struct qmi_info *qmi) return NULL; for (i = 0; i < MAX_CLIENT_NUM; i++) { - if (qmi->fc_info[i].dfc_client) - return qmi->fc_info[i].dfc_client; + if (qmi->dfc_clients[i]) + return qmi->dfc_clients[i]; } return NULL; @@ -364,6 +365,7 @@ static int qmi_rmnet_setup_client(void *port, struct qmi_info *qmi, struct tcmsg *tcm) { int idx, rc, err = 0; + struct svc_info svc; ASSERT_RTNL(); @@ -374,7 +376,7 @@ qmi_rmnet_setup_client(void *port, struct qmi_info *qmi, struct tcmsg *tcm) idx = (tcm->tcm_handle == 0) ? 0 : 1; if (!qmi) { - qmi = kzalloc(sizeof(struct qmi_info), GFP_KERNEL); + qmi = kzalloc(sizeof(struct qmi_info), GFP_ATOMIC); if (!qmi) return -ENOMEM; @@ -382,20 +384,20 @@ qmi_rmnet_setup_client(void *port, struct qmi_info *qmi, struct tcmsg *tcm) } qmi->flag = tcm->tcm_ifindex; - qmi->fc_info[idx].svc.instance = tcm->tcm_handle; - qmi->fc_info[idx].svc.ep_type = tcm->tcm_info; - qmi->fc_info[idx].svc.iface_id = tcm->tcm_parent; + svc.instance = tcm->tcm_handle; + svc.ep_type = tcm->tcm_info; + svc.iface_id = tcm->tcm_parent; if (((tcm->tcm_ifindex & FLAG_DFC_MASK) == DFC_MODE_MULTIQ) && - (qmi->fc_info[idx].dfc_client == NULL)) { - rc = dfc_qmi_client_init(port, idx, qmi); + (qmi->dfc_clients[idx] == NULL)) { + rc = dfc_qmi_client_init(port, idx, &svc); if (rc < 0) err = rc; } if ((tcm->tcm_ifindex & FLAG_POWERSAVE_MASK) && (idx == 0) && (qmi->wda_client == NULL)) { - rc = wda_qmi_client_init(port, tcm->tcm_handle); + rc = wda_qmi_client_init(port, &svc); if (rc < 0) err = rc; } @@ -406,12 +408,11 @@ qmi_rmnet_setup_client(void *port, struct qmi_info *qmi, struct tcmsg *tcm) static int __qmi_rmnet_delete_client(void *port, struct qmi_info *qmi, int idx) { - ASSERT_RTNL(); - if (qmi->fc_info[idx].dfc_client) { - dfc_qmi_client_exit(qmi->fc_info[idx].dfc_client); - qmi->fc_info[idx].dfc_client = NULL; + if (qmi->dfc_clients[idx]) { + dfc_qmi_client_exit(qmi->dfc_clients[idx]); + qmi->dfc_clients[idx] = NULL; } if (!qmi_rmnet_has_client(qmi)) { diff --git a/drivers/soc/qcom/qmi_rmnet_i.h b/drivers/soc/qcom/qmi_rmnet_i.h index 2f7c262d26e6580331505c64bf2124ac605a3285..d076dcbcd40682b03df54c99808a154504e4ef6c 100644 --- a/drivers/soc/qcom/qmi_rmnet_i.h +++ b/drivers/soc/qcom/qmi_rmnet_i.h @@ -51,11 +51,6 @@ struct svc_info { u32 iface_id; }; -struct fc_info { - struct svc_info svc; - void *dfc_client; -}; - struct qos_info { u8 mux_id; struct net_device *real_dev; @@ -74,7 +69,7 @@ struct flow_info { struct qmi_info { int flag; void *wda_client; - struct fc_info fc_info[MAX_CLIENT_NUM]; + void *dfc_clients[MAX_CLIENT_NUM]; unsigned long ps_work_active; int ps_enabled; }; @@ -109,7 +104,7 @@ qmi_rmnet_get_bearer_map(struct qos_info *qos_info, u8 bearer_id); unsigned int qmi_rmnet_grant_per(unsigned int grant); -int dfc_qmi_client_init(void *port, int index, struct qmi_info *qmi); +int dfc_qmi_client_init(void *port, int index, struct svc_info *psvc); void dfc_qmi_client_exit(void *dfc_data); @@ -129,13 +124,13 @@ qmi_rmnet_get_flow_map(struct qos_info *qos_info, } static inline struct rmnet_bearer_map * -qmi_rmnet_get_bearer_map(struct qos_info *qos_info, uint8_t bearer_id) +qmi_rmnet_get_bearer_map(struct qos_info *qos_info, u8 bearer_id) { return NULL; } static inline int -dfc_qmi_client_init(void *port, int modem, struct qmi_info *qmi) +dfc_qmi_client_init(void *port, int index, struct svc_info *psvc) { return -EINVAL; } @@ -157,11 +152,11 @@ dfc_qmi_wq_flush(struct qmi_info *qmi) #endif #ifdef CONFIG_QCOM_QMI_POWER_COLLAPSE -int wda_qmi_client_init(void *port, uint32_t instance); +int wda_qmi_client_init(void *port, struct svc_info *psvc); void wda_qmi_client_exit(void *wda_data); -int wda_set_powersave_mode(void *wda_data, uint8_t enable); +int wda_set_powersave_mode(void *wda_data, u8 enable); #else -static inline int wda_qmi_client_init(void *port, uint32_t instance) +static inline int wda_qmi_client_init(void *port, struct svc_info *psvc) { return -EINVAL; } @@ -170,7 +165,7 @@ static inline void wda_qmi_client_exit(void *wda_data) { } -static inline int wda_set_powersave_mode(void *wda_data, uint8_t enable) +static inline int wda_set_powersave_mode(void *wda_data, u8 enable) { return -EINVAL; } diff --git a/drivers/soc/qcom/smcinvoke.c b/drivers/soc/qcom/smcinvoke.c index 065aa47b579a8384e470cee7cc4a313a56959a45..c15c2420d2275e7845e15eb01167335a70220f63 100644 --- a/drivers/soc/qcom/smcinvoke.c +++ b/drivers/soc/qcom/smcinvoke.c @@ -790,7 +790,7 @@ static int32_t smcinvoke_map_mem_region(void *buf, size_t buf_len) ob->p_addr = mem_obj->p_addr; ob->len = mem_obj->p_addr_len; ob->perms = SMCINVOKE_MEM_PERM_RW; - *oo = mem_obj->mem_map_obj_id; + *oo = TZHANDLE_MAKE_LOCAL(MEM_MAP_SRVR_ID, mem_obj->mem_map_obj_id); out: if (ret != OBJECT_OK) kref_put(&mem_obj->mem_map_obj_ref_cnt, del_mem_map_obj_locked); diff --git a/drivers/soc/qcom/smp2p.c b/drivers/soc/qcom/smp2p.c index fba9c25e043b70f0cce5f65e2181ea0cec162092..f2f90ee18054aff178cf485c1f4a7278ae7e636c 100644 --- a/drivers/soc/qcom/smp2p.c +++ b/drivers/soc/qcom/smp2p.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -133,6 +134,8 @@ struct smp2p_entry { * @ipc_regmap: regmap for the outbound ipc * @ipc_offset: offset within the regmap * @ipc_bit: bit in regmap@offset to kick to signal remote processor + * @mbox_client: mailbox client handle + * @mbox_chan: apcs ipc mailbox channel handle * @inbound: list of inbound entries * @outbound: list of outbound entries */ @@ -158,6 +161,9 @@ struct qcom_smp2p { int ipc_offset; int ipc_bit; + struct mbox_client mbox_client; + struct mbox_chan *mbox_chan; + struct list_head inbound; struct list_head outbound; }; @@ -174,7 +180,13 @@ static void qcom_smp2p_kick(struct qcom_smp2p *smp2p) { /* Make sure any updated data is written before the kick */ wmb(); - regmap_write(smp2p->ipc_regmap, smp2p->ipc_offset, BIT(smp2p->ipc_bit)); + + if (smp2p->mbox_chan) { + mbox_send_message(smp2p->mbox_chan, NULL); + mbox_client_txdone(smp2p->mbox_chan, 0); + } else { + regmap_write(smp2p->ipc_regmap, smp2p->ipc_offset, BIT(smp2p->ipc_bit)); + } } static bool qcom_smp2p_check_ssr(struct qcom_smp2p *smp2p) @@ -555,10 +567,6 @@ static int qcom_smp2p_probe(struct platform_device *pdev) platform_set_drvdata(pdev, smp2p); - ret = smp2p_parse_ipc(smp2p); - if (ret) - return ret; - key = "qcom,smem"; ret = of_property_read_u32_array(pdev->dev.of_node, key, smp2p->smem_items, 2); @@ -585,9 +593,23 @@ static int qcom_smp2p_probe(struct platform_device *pdev) return smp2p->irq; } + smp2p->mbox_client.dev = &pdev->dev; + smp2p->mbox_client.knows_txdone = true; + smp2p->mbox_chan = mbox_request_channel(&smp2p->mbox_client, 0); + if (IS_ERR(smp2p->mbox_chan)) { + if (PTR_ERR(smp2p->mbox_chan) != -ENODEV) + return PTR_ERR(smp2p->mbox_chan); + + smp2p->mbox_chan = NULL; + + ret = smp2p_parse_ipc(smp2p); + if (ret) + return ret; + } + ret = qcom_smp2p_alloc_outbound_item(smp2p); if (ret < 0) - return ret; + goto release_mbox; for_each_available_child_of_node(pdev->dev.of_node, node) { entry = devm_kzalloc(&pdev->dev, sizeof(*entry), GFP_KERNEL); @@ -642,6 +664,9 @@ static int qcom_smp2p_probe(struct platform_device *pdev) smp2p->out->valid_entries = 0; +release_mbox: + mbox_free_channel(smp2p->mbox_chan); + return ret; } @@ -656,6 +681,8 @@ static int qcom_smp2p_remove(struct platform_device *pdev) list_for_each_entry(entry, &smp2p->outbound, node) qcom_smem_state_unregister(entry->state); + mbox_free_channel(smp2p->mbox_chan); + smp2p->out->valid_entries = 0; return 0; diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index e752ad57a83a9887681379fb8e2359cee128d598..7da1a1d976b5d640f575af4c073fb7999db9b04a 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -350,6 +350,9 @@ static struct msm_soc_info cpu_of_id[] = { /* sdmmagpie ID */ [365] = {MSM_CPU_SDMMAGPIE, "SDMMAGPIE"}, + /* trinket ID */ + [394] = {MSM_CPU_TRINKET, "TRINKET"}, + /* Uninitialized IDs are not known to run Linux. * MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are * considered as unknown CPU. @@ -1249,6 +1252,10 @@ static void * __init setup_dummy_socinfo(void) dummy_socinfo.id = 365; strlcpy(dummy_socinfo.build_id, "sdmmagpie - ", sizeof(dummy_socinfo.build_id)); + } else if (early_machine_is_trinket()) { + dummy_socinfo.id = 394; + strlcpy(dummy_socinfo.build_id, "trinket - ", + sizeof(dummy_socinfo.build_id)); } else strlcat(dummy_socinfo.build_id, "Dummy socinfo", sizeof(dummy_socinfo.build_id)); diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c index a19248f07c03dba9fd3db77474e907295831c463..4bac901a2f6c789672fd7df85825b5c17a6e7042 100644 --- a/drivers/soc/qcom/spcom.c +++ b/drivers/soc/qcom/spcom.c @@ -649,7 +649,10 @@ static int spcom_handle_send_command(struct spcom_channel *ch, mutex_unlock(&ch->lock); msleep(TX_RETRY_DELAY_MSEC); mutex_lock(&ch->lock); - } while (ret == -EAGAIN && time_msec < timeout_msec); + } while ((ret == -EBUSY || ret == -EAGAIN) && time_msec < timeout_msec); + if (ret) + pr_err("ch [%s] rpmsg_trysend() error (%d), timeout_msec=%d\n", + ch->name, ret, timeout_msec); mutex_unlock(&ch->lock); kfree(tx_buf); @@ -853,7 +856,11 @@ static int spcom_handle_send_modified_command(struct spcom_channel *ch, mutex_unlock(&ch->lock); msleep(TX_RETRY_DELAY_MSEC); mutex_lock(&ch->lock); - } while (ret == -EAGAIN && time_msec < timeout_msec); + } while ((ret == -EBUSY || ret == -EAGAIN) && time_msec < timeout_msec); + if (ret) + pr_err("ch [%s] rpmsg_trysend() error (%d), timeout_msec=%d\n", + ch->name, ret, timeout_msec); + mutex_unlock(&ch->lock); memset(tx_buf, 0, tx_buf_size); kfree(tx_buf); @@ -1425,7 +1432,7 @@ static ssize_t spcom_device_write(struct file *filp, if (ret) { pr_err("handle command error [%d].\n", ret); kfree(buf); - return -EFAULT; + return ret; } kfree(buf); diff --git a/drivers/soc/qcom/subsystem_notif.c b/drivers/soc/qcom/subsystem_notif.c index b79d988cc304e8efd3c654710adb21ce51013b4c..e6d0f12a20250d3d81c54d64cc544924cf89e67e 100644 --- a/drivers/soc/qcom/subsystem_notif.c +++ b/drivers/soc/qcom/subsystem_notif.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011, 2013, 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011, 2013, 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -28,10 +28,25 @@ #include #include +/** + * The callbacks that are registered in this data structure as early + * notification callbacks will be called as soon as the SSR framework is + * informed that the subsystem has crashed. This means that these functions will + * be invoked as part of an IRQ handler, and thus, will be called in an atomic + * context. Therefore, functions that are registered as early notification + * callback must obey to the same constraints as interrupt handlers + * (i.e. these functions must not sleep or block, etc). + */ +struct subsys_early_notif_info { + spinlock_t cb_lock; + void (*early_notif_cb[NUM_EARLY_NOTIFS])(void *); + void *data[NUM_EARLY_NOTIFS]; +}; struct subsys_notif_info { char name[50]; struct srcu_notifier_head subsys_notif_rcvr_list; + struct subsys_early_notif_info early_notif_info; struct list_head list; }; @@ -101,6 +116,105 @@ int subsys_notif_unregister_notifier(void *subsys_handle, } EXPORT_SYMBOL(subsys_notif_unregister_notifier); +void send_early_notifications(void *early_notif_handle) +{ + struct subsys_early_notif_info *early_info = early_notif_handle; + unsigned long flags; + unsigned int i; + void (*notif_cb)(void *); + + if (!early_notif_handle) + return; + + spin_lock_irqsave(&early_info->cb_lock, flags); + for (i = 0; i < NUM_EARLY_NOTIFS; i++) { + notif_cb = early_info->early_notif_cb[i]; + if (notif_cb) + notif_cb(early_info->data[i]); + } + spin_unlock_irqrestore(&early_info->cb_lock, flags); +} +EXPORT_SYMBOL(send_early_notifications); + +static bool valid_early_notif(enum early_subsys_notif_type notif_type) +{ + return notif_type >= 0 && notif_type < NUM_EARLY_NOTIFS; +} + +/** + * The early_notif_cb parameter must point to a function that conforms to the + * same constraints placed upon interrupt handlers, as the function will be + * called in an atomic context (i.e. these functions must not sleep or block). + */ +int subsys_register_early_notifier(const char *subsys_name, + enum early_subsys_notif_type notif_type, + void (*early_notif_cb)(void *), void *data) +{ + struct subsys_notif_info *subsys; + struct subsys_early_notif_info *early_notif_info; + unsigned long flags; + int rc = 0; + + if (!subsys_name || !early_notif_cb || !valid_early_notif(notif_type)) + return -EINVAL; + + subsys = _notif_find_subsys(subsys_name); + if (!subsys) + return -EINVAL; + + early_notif_info = &subsys->early_notif_info; + spin_lock_irqsave(&early_notif_info->cb_lock, flags); + if (early_notif_info->early_notif_cb[notif_type]) { + rc = -EEXIST; + goto out; + } + early_notif_info->early_notif_cb[notif_type] = early_notif_cb; + early_notif_info->data[notif_type] = data; +out: + spin_unlock_irqrestore(&early_notif_info->cb_lock, flags); + return rc; +} +EXPORT_SYMBOL(subsys_register_early_notifier); + +int subsys_unregister_early_notifier(const char *subsys_name, enum + early_subsys_notif_type notif_type) +{ + struct subsys_notif_info *subsys; + struct subsys_early_notif_info *early_notif_info; + unsigned long flags; + + if (!subsys_name || !valid_early_notif(notif_type)) + return -EINVAL; + + subsys = _notif_find_subsys(subsys_name); + if (!subsys) + return -EINVAL; + + early_notif_info = &subsys->early_notif_info; + spin_lock_irqsave(&early_notif_info->cb_lock, flags); + early_notif_info->early_notif_cb[notif_type] = NULL; + early_notif_info->data[notif_type] = NULL; + spin_unlock_irqrestore(&early_notif_info->cb_lock, flags); + return 0; +} +EXPORT_SYMBOL(subsys_unregister_early_notifier); + +void *subsys_get_early_notif_info(const char *subsys_name) +{ + struct subsys_notif_info *subsys; + + if (!subsys_name) + return ERR_PTR(-EINVAL); + + subsys = _notif_find_subsys(subsys_name); + + if (!subsys) + return ERR_PTR(-EINVAL); + + return &subsys->early_notif_info; +} +EXPORT_SYMBOL(subsys_get_early_notif_info); + void *subsys_notif_add_subsys(const char *subsys_name) { struct subsys_notif_info *subsys = NULL; @@ -128,6 +242,9 @@ void *subsys_notif_add_subsys(const char *subsys_name) srcu_init_notifier_head(&subsys->subsys_notif_rcvr_list); + memset(&subsys->early_notif_info, 0, sizeof(struct + subsys_early_notif_info)); + spin_lock_init(&subsys->early_notif_info.cb_lock); INIT_LIST_HEAD(&subsys->list); mutex_lock(¬if_lock); diff --git a/drivers/soc/qcom/subsystem_restart.c b/drivers/soc/qcom/subsystem_restart.c index 9c6a1bf950c7f2d19ec8a18a44f4769f9b4e4ba0..1b3e54c9b5a6d0ca991a0954611ec25d2f077521 100644 --- a/drivers/soc/qcom/subsystem_restart.c +++ b/drivers/soc/qcom/subsystem_restart.c @@ -62,7 +62,7 @@ module_param(enable_debug, int, 0644); #define setup_timeout(dest_ss, source_ss, comm_type) \ _setup_timeout(dest_ss, source_ss, comm_type) -#define cancel_timeout(subsys) del_timer(&subsys->timeout_data.timer) +#define cancel_timeout(subsys) del_timer_sync(&subsys->timeout_data.timer) #define init_subsys_timer(subsys) _init_subsys_timer(subsys) /* Timeout values */ @@ -194,6 +194,7 @@ struct subsys_device { struct subsys_tracking track; void *notify; + void *early_notify; struct device dev; struct module *owner; int count; @@ -1227,6 +1228,8 @@ int subsystem_restart_dev(struct subsys_device *dev) name = dev->desc->name; + send_early_notifications(dev->early_notify); + /* * If a system reboot/shutdown is underway, ignore subsystem errors. * However, print a message so that we know that a subsystem behaved @@ -1801,6 +1804,7 @@ struct subsys_device *subsys_register(struct subsys_desc *desc) sizeof(subsys->desc->fw_name)); subsys->notify = subsys_notif_add_subsys(desc->name); + subsys->early_notify = subsys_get_early_notif_info(desc->name); snprintf(subsys->wlname, sizeof(subsys->wlname), "ssr(%s)", desc->name); wakeup_source_init(&subsys->ssr_wlock, subsys->wlname); diff --git a/drivers/soc/qcom/wda_qmi.c b/drivers/soc/qcom/wda_qmi.c index 8e34aad2574ba1fa592121a79e13d31baee20938..6dcc7c58f948b7293dbc9c353b7137d6cb95d811 100644 --- a/drivers/soc/qcom/wda_qmi.c +++ b/drivers/soc/qcom/wda_qmi.c @@ -11,6 +11,7 @@ * */ +#include #include #include #define CREATE_TRACE_POINTS @@ -23,6 +24,7 @@ struct wda_qmi_data { struct work_struct svc_arrive; struct qmi_handle handle; struct sockaddr_qrtr ssctl; + struct svc_info svc; }; static void wda_svc_config(struct work_struct *work); @@ -255,8 +257,7 @@ static int wda_set_powersave_mode_req(void *wda_data, uint8_t enable) return ret; } -static int wda_set_powersave_config_req(struct qmi_handle *wda_handle, - struct qmi_info *qmi) +static int wda_set_powersave_config_req(struct qmi_handle *wda_handle) { struct wda_qmi_data *data = container_of(wda_handle, struct wda_qmi_data, handle); @@ -283,8 +284,8 @@ static int wda_set_powersave_config_req(struct qmi_handle *wda_handle, goto out; } - req->ep_id.ep_type = qmi->fc_info[0].svc.ep_type; - req->ep_id.iface_id = qmi->fc_info[0].svc.iface_id; + req->ep_id.ep_type = data->svc.ep_type; + req->ep_id.iface_id = data->svc.iface_id; req->req_data_cfg_valid = 1; req->req_data_cfg = WDA_DATA_POWERSAVE_CONFIG_ALL_MASK_V01; ret = qmi_send_request(wda_handle, &data->ssctl, &txn, @@ -319,20 +320,25 @@ static void wda_svc_config(struct work_struct *work) svc_arrive); struct qmi_info *qmi; - qmi = (struct qmi_info *)rmnet_get_qmi_pt(data->rmnet_port); - if (!qmi) - goto clean_out; - - if (wda_set_powersave_config_req(&data->handle, qmi) < 0) { + if (wda_set_powersave_config_req(&data->handle) < 0) { pr_err("%s() failed, qmi handle pt: %p\n", __func__, &data->handle); goto clean_out; } - trace_wda_client_state_up(qmi->fc_info[0].svc.instance, - qmi->fc_info[0].svc.ep_type, - qmi->fc_info[0].svc.iface_id); + trace_wda_client_state_up(data->svc.instance, + data->svc.ep_type, + data->svc.iface_id); + rtnl_lock(); + qmi = (struct qmi_info *)rmnet_get_qmi_pt(data->rmnet_port); + if (!qmi) { + rtnl_unlock(); + goto clean_out; + } + qmi->wda_client = (void *)data; + rtnl_unlock(); + pr_info("Connection established with the WDA Service\n"); return; @@ -370,7 +376,7 @@ static struct qmi_ops server_ops = { .del_server = wda_svc_exit, }; -int wda_qmi_client_init(void *port, uint32_t instance) +int wda_qmi_client_init(void *port, struct svc_info *psvc) { struct wda_qmi_data *data; int rc = 0; @@ -392,6 +398,7 @@ int wda_qmi_client_init(void *port, uint32_t instance) } data->rmnet_port = port; + memcpy(&data->svc, psvc, sizeof(data->svc)); INIT_WORK(&data->svc_arrive, wda_svc_config); rc = qmi_handle_init(&data->handle, @@ -404,7 +411,7 @@ int wda_qmi_client_init(void *port, uint32_t instance) } rc = qmi_add_lookup(&data->handle, WDA_SERVICE_ID_V01, - WDA_SERVICE_VERS_V01, instance); + WDA_SERVICE_VERS_V01, psvc->instance); if (rc < 0) { pr_err("%s(): Failed qmi_add_lookup, err: %d\n", __func__, rc); qmi_handle_release(&data->handle); diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index 4a001634023e09b8e83b8e6b82b5af557e2c0853..02bd1eba045b8b6bc915ff44b076481971c7d1d6 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -319,7 +319,7 @@ static void cdns_spi_fill_tx_fifo(struct cdns_spi *xspi) */ if (cdns_spi_read(xspi, CDNS_SPI_ISR) & CDNS_SPI_IXR_TXFULL) - usleep_range(10, 20); + udelay(10); if (xspi->txbuf) cdns_spi_write(xspi, CDNS_SPI_TXD, *xspi->txbuf++); diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 6ddb6ef1fda4ff0900b97d7b87942bbe9935475d..c5bbe08771a4d06894e14b284a589f2149d58f02 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -217,7 +217,7 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) pdata = &dspi->pdata; /* program delay transfers if tx_delay is non zero */ - if (spicfg->wdelay) + if (spicfg && spicfg->wdelay) spidat1 |= SPIDAT1_WDEL; /* diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index d89127f4a46dfd567e2c7cfb290833d038c930ed..ca013dd4ff6bb19d410ae522fe1f91b27d5f7ace 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -1006,30 +1006,30 @@ static int dspi_probe(struct platform_device *pdev) goto out_master_put; } + dspi->clk = devm_clk_get(&pdev->dev, "dspi"); + if (IS_ERR(dspi->clk)) { + ret = PTR_ERR(dspi->clk); + dev_err(&pdev->dev, "unable to get clock\n"); + goto out_master_put; + } + ret = clk_prepare_enable(dspi->clk); + if (ret) + goto out_master_put; + dspi_init(dspi); dspi->irq = platform_get_irq(pdev, 0); if (dspi->irq < 0) { dev_err(&pdev->dev, "can't get platform irq\n"); ret = dspi->irq; - goto out_master_put; + goto out_clk_put; } ret = devm_request_irq(&pdev->dev, dspi->irq, dspi_interrupt, 0, pdev->name, dspi); if (ret < 0) { dev_err(&pdev->dev, "Unable to attach DSPI interrupt\n"); - goto out_master_put; - } - - dspi->clk = devm_clk_get(&pdev->dev, "dspi"); - if (IS_ERR(dspi->clk)) { - ret = PTR_ERR(dspi->clk); - dev_err(&pdev->dev, "unable to get clock\n"); - goto out_master_put; + goto out_clk_put; } - ret = clk_prepare_enable(dspi->clk); - if (ret) - goto out_master_put; if (dspi->devtype_data->trans_mode == DSPI_DMA_MODE) { ret = dspi_request_dma(dspi, res->start); diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 4cb515a3104c1759b451c1f2d313953c009fb3ce..3a2e46e49405b5ea2bd2e17f982d4298578b72ae 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -1480,6 +1480,10 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = { { PCI_VDEVICE(INTEL, 0x31c2), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x31c4), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x31c6), LPSS_BXT_SSP }, + /* ICL-LP */ + { PCI_VDEVICE(INTEL, 0x34aa), LPSS_CNL_SSP }, + { PCI_VDEVICE(INTEL, 0x34ab), LPSS_CNL_SSP }, + { PCI_VDEVICE(INTEL, 0x34fb), LPSS_CNL_SSP }, /* APL */ { PCI_VDEVICE(INTEL, 0x5ac2), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x5ac4), LPSS_BXT_SSP }, diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 2a10b3f94ff72a4ea3d6924a082ef6d2db174528..20981e08ee975d197c63845fcce11e0c76e53e8d 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -598,11 +598,13 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx, ret = wait_event_interruptible_timeout(rspi->wait, rspi->dma_callbacked, HZ); - if (ret > 0 && rspi->dma_callbacked) + if (ret > 0 && rspi->dma_callbacked) { ret = 0; - else if (!ret) { - dev_err(&rspi->master->dev, "DMA timeout\n"); - ret = -ETIMEDOUT; + } else { + if (!ret) { + dev_err(&rspi->master->dev, "DMA timeout\n"); + ret = -ETIMEDOUT; + } if (tx) dmaengine_terminate_all(rspi->master->dma_tx); if (rx) @@ -1352,12 +1354,36 @@ static const struct platform_device_id spi_driver_ids[] = { MODULE_DEVICE_TABLE(platform, spi_driver_ids); +#ifdef CONFIG_PM_SLEEP +static int rspi_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct rspi_data *rspi = platform_get_drvdata(pdev); + + return spi_master_suspend(rspi->master); +} + +static int rspi_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct rspi_data *rspi = platform_get_drvdata(pdev); + + return spi_master_resume(rspi->master); +} + +static SIMPLE_DEV_PM_OPS(rspi_pm_ops, rspi_suspend, rspi_resume); +#define DEV_PM_OPS &rspi_pm_ops +#else +#define DEV_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + static struct platform_driver rspi_driver = { .probe = rspi_probe, .remove = rspi_remove, .id_table = spi_driver_ids, .driver = { .name = "renesas_spi", + .pm = DEV_PM_OPS, .of_match_table = of_match_ptr(rspi_of_match), }, }; diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 0fea18ab970e30424d0799f0b265d24f6d26dfc2..db2a529accae8471352ee54b70f19ef4a0fc2483 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -384,7 +384,8 @@ static void sh_msiof_spi_set_mode_regs(struct sh_msiof_spi_priv *p, static void sh_msiof_reset_str(struct sh_msiof_spi_priv *p) { - sh_msiof_write(p, STR, sh_msiof_read(p, STR)); + sh_msiof_write(p, STR, + sh_msiof_read(p, STR) & ~(STR_TDREQ | STR_RDREQ)); } static void sh_msiof_spi_write_fifo_8(struct sh_msiof_spi_priv *p, @@ -1361,12 +1362,37 @@ static const struct platform_device_id spi_driver_ids[] = { }; MODULE_DEVICE_TABLE(platform, spi_driver_ids); +#ifdef CONFIG_PM_SLEEP +static int sh_msiof_spi_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct sh_msiof_spi_priv *p = platform_get_drvdata(pdev); + + return spi_master_suspend(p->master); +} + +static int sh_msiof_spi_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct sh_msiof_spi_priv *p = platform_get_drvdata(pdev); + + return spi_master_resume(p->master); +} + +static SIMPLE_DEV_PM_OPS(sh_msiof_spi_pm_ops, sh_msiof_spi_suspend, + sh_msiof_spi_resume); +#define DEV_PM_OPS &sh_msiof_spi_pm_ops +#else +#define DEV_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + static struct platform_driver sh_msiof_spi_drv = { .probe = sh_msiof_spi_probe, .remove = sh_msiof_spi_remove, .id_table = spi_driver_ids, .driver = { .name = "spi_sh_msiof", + .pm = DEV_PM_OPS, .of_match_table = of_match_ptr(sh_msiof_match), }, }; diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index 3e12d5f87ee4412b086649c8f2312fb3cc9e30a8..9831c1106945e835d6f8891569a8adc9bbcdc42a 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -1063,6 +1063,24 @@ static int tegra_slink_probe(struct platform_device *pdev) goto exit_free_master; } + /* disabled clock may cause interrupt storm upon request */ + tspi->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(tspi->clk)) { + ret = PTR_ERR(tspi->clk); + dev_err(&pdev->dev, "Can not get clock %d\n", ret); + goto exit_free_master; + } + ret = clk_prepare(tspi->clk); + if (ret < 0) { + dev_err(&pdev->dev, "Clock prepare failed %d\n", ret); + goto exit_free_master; + } + ret = clk_enable(tspi->clk); + if (ret < 0) { + dev_err(&pdev->dev, "Clock enable failed %d\n", ret); + goto exit_free_master; + } + spi_irq = platform_get_irq(pdev, 0); tspi->irq = spi_irq; ret = request_threaded_irq(tspi->irq, tegra_slink_isr, @@ -1071,14 +1089,7 @@ static int tegra_slink_probe(struct platform_device *pdev) if (ret < 0) { dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n", tspi->irq); - goto exit_free_master; - } - - tspi->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(tspi->clk)) { - dev_err(&pdev->dev, "can not get clock\n"); - ret = PTR_ERR(tspi->clk); - goto exit_free_irq; + goto exit_clk_disable; } tspi->rst = devm_reset_control_get_exclusive(&pdev->dev, "spi"); @@ -1138,6 +1149,8 @@ static int tegra_slink_probe(struct platform_device *pdev) tegra_slink_deinit_dma_param(tspi, true); exit_free_irq: free_irq(spi_irq, tspi); +exit_clk_disable: + clk_disable(tspi->clk); exit_free_master: spi_master_put(master); return ret; @@ -1150,6 +1163,8 @@ static int tegra_slink_remove(struct platform_device *pdev) free_irq(tspi->irq, tspi); + clk_disable(tspi->clk); + if (tspi->tx_dma_chan) tegra_slink_deinit_dma_param(tspi, false); diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index f85d30dc91878dbb8472b3bc8fec69ff2244fb6a..670dbb7a8500a228e4c7d13e1aad192b5a2e8d7d 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2108,8 +2108,17 @@ int spi_register_controller(struct spi_controller *ctlr) */ if (ctlr->num_chipselect == 0) return -EINVAL; - /* allocate dynamic bus number using Linux idr */ - if ((ctlr->bus_num < 0) && ctlr->dev.of_node) { + if (ctlr->bus_num >= 0) { + /* devices with a fixed bus num must check-in with the num */ + mutex_lock(&board_lock); + id = idr_alloc(&spi_master_idr, ctlr, ctlr->bus_num, + ctlr->bus_num + 1, GFP_KERNEL); + mutex_unlock(&board_lock); + if (WARN(id < 0, "couldn't get idr")) + return id == -ENOSPC ? -EBUSY : id; + ctlr->bus_num = id; + } else if (ctlr->dev.of_node) { + /* allocate dynamic bus number using Linux idr */ id = of_alias_get_id(ctlr->dev.of_node, "spi"); if (id >= 0) { ctlr->bus_num = id; diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index 6985e6cc434ef07c682b589b48f3b617ab5ede57..5257b814417a5d7f852eb11f2633500a1f2d4943 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -645,8 +645,12 @@ static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type) type.type |= BIT(irq); if (flow_type & IRQF_TRIGGER_RISING) type.polarity_high |= BIT(irq); + else + type.polarity_high &= ~BIT(irq); if (flow_type & IRQF_TRIGGER_FALLING) type.polarity_low |= BIT(irq); + else + type.polarity_low &= ~BIT(irq); flow_handler = handle_edge_irq; } else { @@ -655,10 +659,13 @@ static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type) return -EINVAL; type.type &= ~BIT(irq); /* level trig */ - if (flow_type & IRQF_TRIGGER_HIGH) + if (flow_type & IRQF_TRIGGER_HIGH) { type.polarity_high |= BIT(irq); - else + type.polarity_low &= ~BIT(irq); + } else { type.polarity_low |= BIT(irq); + type.polarity_high &= ~BIT(irq); + } flow_handler = handle_level_irq; } diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c index 9dc534f677d1b434c504948a1e652416e95ff28f..aebfe997af9151cfd9b350c60a7e511cb19fb70b 100644 --- a/drivers/staging/android/ashmem.c +++ b/drivers/staging/android/ashmem.c @@ -387,6 +387,12 @@ static int ashmem_mmap(struct file *file, struct vm_area_struct *vma) goto out; } + /* requested mapping size larger than object size */ + if (vma->vm_end - vma->vm_start > PAGE_ALIGN(asma->size)) { + ret = -EINVAL; + goto out; + } + /* requested protection bits must match our allowed protection mask */ if (unlikely((vma->vm_flags & ~calc_vm_prot_bits(asma->prot_mask, 0)) & calc_vm_prot_bits(PROT_MASK, 0))) { diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 2240c4ae61ce28f97177dfd2ddb4796853288a69..fe81a283ad142132fae067da59cc72a12c731856 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -505,6 +505,7 @@ static void ion_dma_buf_release(struct dma_buf *dmabuf) struct ion_buffer *buffer = dmabuf->priv; _ion_buffer_destroy(buffer); + kfree(dmabuf->exp_name); } static void *ion_dma_buf_kmap(struct dma_buf *dmabuf, unsigned long offset) @@ -1047,6 +1048,7 @@ struct dma_buf *ion_alloc_dmabuf(size_t len, unsigned int heap_id_mask, struct ion_heap *heap; DEFINE_DMA_BUF_EXPORT_INFO(exp_info); struct dma_buf *dmabuf; + char task_comm[TASK_COMM_LEN]; pr_debug("%s: len %zu heap_id_mask %u flags %x\n", __func__, len, heap_id_mask, flags); @@ -1078,14 +1080,20 @@ struct dma_buf *ion_alloc_dmabuf(size_t len, unsigned int heap_id_mask, if (IS_ERR(buffer)) return ERR_CAST(buffer); + get_task_comm(task_comm, current->group_leader); + exp_info.ops = &dma_buf_ops; exp_info.size = buffer->size; exp_info.flags = O_RDWR; exp_info.priv = buffer; + exp_info.exp_name = kasprintf(GFP_KERNEL, "%s-%s-%d-%s", KBUILD_MODNAME, + heap->name, current->tgid, task_comm); dmabuf = dma_buf_export(&exp_info); - if (IS_ERR(dmabuf)) + if (IS_ERR(dmabuf)) { _ion_buffer_destroy(buffer); + kfree(dmabuf->exp_name); + } return dmabuf; } diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index 2cac160993bbd82f12246951e7db109b5fc043ac..158f3e83efb66d75daf0785f298da811900a9252 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -5453,11 +5453,11 @@ static int ni_E_init(struct comedi_device *dev, /* Digital I/O (PFI) subdevice */ s = &dev->subdevices[NI_PFI_DIO_SUBDEV]; s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; s->maxdata = 1; if (devpriv->is_m_series) { s->n_chan = 16; s->insn_bits = ni_pfi_insn_bits; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; ni_writew(dev, s->state, NI_M_PFI_DO_REG); for (i = 0; i < NUM_PFI_OUTPUT_SELECT_REGS; ++i) { @@ -5466,6 +5466,7 @@ static int ni_E_init(struct comedi_device *dev, } } else { s->n_chan = 10; + s->subdev_flags = SDF_INTERNAL; } s->insn_config = ni_pfi_insn_config; diff --git a/drivers/staging/irda/net/af_irda.c b/drivers/staging/irda/net/af_irda.c index 23fa7c8b09a5861e2acc042775830cc2dac4e0f4..cebe9878ca03629d054bb91e0fe309ca9a370615 100644 --- a/drivers/staging/irda/net/af_irda.c +++ b/drivers/staging/irda/net/af_irda.c @@ -775,6 +775,13 @@ static int irda_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) return -EINVAL; lock_sock(sk); + + /* Ensure that the socket is not already bound */ + if (self->ias_obj) { + err = -EINVAL; + goto out; + } + #ifdef CONFIG_IRDA_ULTRA /* Special care for Ultra sockets */ if ((sk->sk_type == SOCK_DGRAM) && @@ -2012,7 +2019,11 @@ static int irda_setsockopt(struct socket *sock, int level, int optname, err = -EINVAL; goto out; } - irias_insert_object(ias_obj); + + /* Only insert newly allocated objects */ + if (free_ias) + irias_insert_object(ias_obj); + kfree(ias_opt); break; case IRLMP_IAS_DEL: diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c b/drivers/staging/media/imx/imx-ic-prpencvf.c index 0790b3d9e25560366a48633ddce37beeea21e762..111afd34aa3c328e385d09fcdb0f4c19dbc1e6cb 100644 --- a/drivers/staging/media/imx/imx-ic-prpencvf.c +++ b/drivers/staging/media/imx/imx-ic-prpencvf.c @@ -210,6 +210,7 @@ static void prp_vb2_buf_done(struct prp_priv *priv, struct ipuv3_channel *ch) done = priv->active_vb2_buf[priv->ipu_buf_num]; if (done) { + done->vbuf.field = vdev->fmt.fmt.pix.field; vb = &done->vbuf.vb2_buf; vb->timestamp = ktime_get_ns(); vb2_buffer_done(vb, priv->nfb4eof ? diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index 6d856118c223285702913468b29200e26c448a7c..83ecb5b2fb9e18c66426f56d18f8379f3cbdab9c 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -171,6 +171,7 @@ static void csi_vb2_buf_done(struct csi_priv *priv) done = priv->active_vb2_buf[priv->ipu_buf_num]; if (done) { + done->vbuf.field = vdev->fmt.fmt.pix.field; vb = &done->vbuf.vb2_buf; vb->timestamp = ktime_get_ns(); vb2_buffer_done(vb, priv->nfb4eof ? diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c index 9e2f0421a01eadd561e0fd1b247e95dc3f40ee65..0bf6643cca0722f1be7aa2d03d553faeaa6383db 100644 --- a/drivers/staging/media/omap4iss/iss_video.c +++ b/drivers/staging/media/omap4iss/iss_video.c @@ -11,7 +11,6 @@ * (at your option) any later version. */ -#include #include #include #include @@ -24,6 +23,8 @@ #include #include +#include + #include "iss_video.h" #include "iss.h" diff --git a/drivers/staging/rts5208/sd.c b/drivers/staging/rts5208/sd.c index 4033a2cf7ac9b3b7028f84f7ea54f753a75536a4..d98d5fe25a17d755e6fe9ba19ba7474ff7233fcb 100644 --- a/drivers/staging/rts5208/sd.c +++ b/drivers/staging/rts5208/sd.c @@ -5002,7 +5002,7 @@ int sd_execute_write_data(struct scsi_cmnd *srb, struct rtsx_chip *chip) goto sd_execute_write_cmd_failed; } - rtsx_write_register(chip, SD_BYTE_CNT_L, 0xFF, 0x00); + retval = rtsx_write_register(chip, SD_BYTE_CNT_L, 0xFF, 0x00); if (retval != STATUS_SUCCESS) { rtsx_trace(chip); goto sd_execute_write_cmd_failed; diff --git a/drivers/staging/typec/tcpm.c b/drivers/staging/typec/tcpm.c index 8af62e74d54c6319678f315a48e302a761dbb71c..f237e31926f4cfc13be67b2f0432cc429e750e7c 100644 --- a/drivers/staging/typec/tcpm.c +++ b/drivers/staging/typec/tcpm.c @@ -2479,7 +2479,8 @@ static void run_state_machine(struct tcpm_port *port) tcpm_port_is_sink(port) && time_is_after_jiffies(port->delayed_runtime)) { tcpm_set_state(port, SNK_DISCOVERY, - port->delayed_runtime - jiffies); + jiffies_to_msecs(port->delayed_runtime - + jiffies)); break; } tcpm_set_state(port, unattached_state(port), 0); diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c index 4be864dbd41c9f4eb63f03361a0dab1e13c54a67..9eb3b625a1b18b46fa940c96a9c5893ca44cade0 100644 --- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c +++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c @@ -442,16 +442,16 @@ int bcm2835_audio_open(struct bcm2835_alsa_stream *alsa_stream) my_workqueue_init(alsa_stream); ret = bcm2835_audio_open_connection(alsa_stream); - if (ret) { - ret = -1; - goto exit; - } + if (ret) + goto free_wq; + instance = alsa_stream->instance; LOG_DBG(" instance (%p)\n", instance); if (mutex_lock_interruptible(&instance->vchi_mutex)) { LOG_DBG("Interrupted whilst waiting for lock on (%d)\n", instance->num_connections); - return -EINTR; + ret = -EINTR; + goto free_wq; } vchi_service_use(instance->vchi_handle[0]); @@ -474,7 +474,11 @@ int bcm2835_audio_open(struct bcm2835_alsa_stream *alsa_stream) unlock: vchi_service_release(instance->vchi_handle[0]); mutex_unlock(&instance->vchi_mutex); -exit: + +free_wq: + if (ret) + destroy_workqueue(alsa_stream->my_wq); + return ret; } diff --git a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c index be936b8fe317599b132988f0a700ec7f7df15af6..377da037f31c3071499c43516395a0bd2745592f 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c +++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c @@ -580,6 +580,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) static void stop_streaming(struct vb2_queue *vq) { int ret; + unsigned long timeout; struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq); v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p\n", @@ -605,10 +606,10 @@ static void stop_streaming(struct vb2_queue *vq) sizeof(dev->capture.frame_count)); /* wait for last frame to complete */ - ret = wait_for_completion_timeout(&dev->capture.frame_cmplt, HZ); - if (ret <= 0) + timeout = wait_for_completion_timeout(&dev->capture.frame_cmplt, HZ); + if (timeout == 0) v4l2_err(&dev->v4l2_dev, - "error %d waiting for frame completion\n", ret); + "timed out waiting for frame completion\n"); v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "disabling connection\n"); diff --git a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c index 4360db6d43927d071803255679ce789fd7dcd604..b3176f42c8207f6a54a6c3927a54b36f5571b3e0 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c +++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c @@ -834,6 +834,7 @@ static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance, { struct mmal_msg_context *msg_context; int ret; + unsigned long timeout; /* payload size must not cause message to exceed max size */ if (payload_len > @@ -872,11 +873,11 @@ static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance, return ret; } - ret = wait_for_completion_timeout(&msg_context->u.sync.cmplt, 3 * HZ); - if (ret <= 0) { - pr_err("error %d waiting for sync completion\n", ret); - if (ret == 0) - ret = -ETIME; + timeout = wait_for_completion_timeout(&msg_context->u.sync.cmplt, + 3 * HZ); + if (timeout == 0) { + pr_err("timed out waiting for sync completion\n"); + ret = -ETIME; /* todo: what happens if the message arrives after aborting */ release_msg_context(msg_context); return ret; diff --git a/drivers/target/iscsi/cxgbit/cxgbit_target.c b/drivers/target/iscsi/cxgbit/cxgbit_target.c index 514986b57c2d60ce19c1074f4d19d65dd550be2e..25eb3891e34b8435fe15b80c5b7eb5e2a7b7c6d6 100644 --- a/drivers/target/iscsi/cxgbit/cxgbit_target.c +++ b/drivers/target/iscsi/cxgbit/cxgbit_target.c @@ -652,6 +652,7 @@ static int cxgbit_set_iso_npdu(struct cxgbit_sock *csk) struct iscsi_param *param; u32 mrdsl, mbl; u32 max_npdu, max_iso_npdu; + u32 max_iso_payload; if (conn->login->leading_connection) { param = iscsi_find_param_from_key(MAXBURSTLENGTH, @@ -670,8 +671,10 @@ static int cxgbit_set_iso_npdu(struct cxgbit_sock *csk) mrdsl = conn_ops->MaxRecvDataSegmentLength; max_npdu = mbl / mrdsl; - max_iso_npdu = CXGBIT_MAX_ISO_PAYLOAD / - (ISCSI_HDR_LEN + mrdsl + + max_iso_payload = rounddown(CXGBIT_MAX_ISO_PAYLOAD, csk->emss); + + max_iso_npdu = max_iso_payload / + (ISCSI_HDR_LEN + mrdsl + cxgbit_digest_len[csk->submode]); csk->max_iso_npdu = min(max_npdu, max_iso_npdu); @@ -741,6 +744,9 @@ static int cxgbit_set_params(struct iscsi_conn *conn) if (conn_ops->MaxRecvDataSegmentLength > cdev->mdsl) conn_ops->MaxRecvDataSegmentLength = cdev->mdsl; + if (cxgbit_set_digest(csk)) + return -1; + if (conn->login->leading_connection) { param = iscsi_find_param_from_key(ERRORRECOVERYLEVEL, conn->param_list); @@ -764,7 +770,7 @@ static int cxgbit_set_params(struct iscsi_conn *conn) if (is_t5(cdev->lldi.adapter_type)) goto enable_ddp; else - goto enable_digest; + return 0; } if (test_bit(CDEV_ISO_ENABLE, &cdev->flags)) { @@ -781,10 +787,6 @@ static int cxgbit_set_params(struct iscsi_conn *conn) } } -enable_digest: - if (cxgbit_set_digest(csk)) - return -1; - return 0; } diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c index 9518ffd8b8bac81cc1b725046857d5f229e58b15..4e680d753941f71ea299d87b6c0cd18fc307b50f 100644 --- a/drivers/target/iscsi/iscsi_target_auth.c +++ b/drivers/target/iscsi/iscsi_target_auth.c @@ -26,27 +26,6 @@ #include "iscsi_target_nego.h" #include "iscsi_target_auth.h" -static int chap_string_to_hex(unsigned char *dst, unsigned char *src, int len) -{ - int j = DIV_ROUND_UP(len, 2), rc; - - rc = hex2bin(dst, src, j); - if (rc < 0) - pr_debug("CHAP string contains non hex digit symbols\n"); - - dst[j] = '\0'; - return j; -} - -static void chap_binaryhex_to_asciihex(char *dst, char *src, int src_len) -{ - int i; - - for (i = 0; i < src_len; i++) { - sprintf(&dst[i*2], "%02x", (int) src[i] & 0xff); - } -} - static int chap_gen_challenge( struct iscsi_conn *conn, int caller, @@ -62,7 +41,7 @@ static int chap_gen_challenge( ret = get_random_bytes_wait(chap->challenge, CHAP_CHALLENGE_LENGTH); if (unlikely(ret)) return ret; - chap_binaryhex_to_asciihex(challenge_asciihex, chap->challenge, + bin2hex(challenge_asciihex, chap->challenge, CHAP_CHALLENGE_LENGTH); /* * Set CHAP_C, and copy the generated challenge into c_str. @@ -248,9 +227,16 @@ static int chap_server_compute_md5( pr_err("Could not find CHAP_R.\n"); goto out; } + if (strlen(chap_r) != MD5_SIGNATURE_SIZE * 2) { + pr_err("Malformed CHAP_R\n"); + goto out; + } + if (hex2bin(client_digest, chap_r, MD5_SIGNATURE_SIZE) < 0) { + pr_err("Malformed CHAP_R\n"); + goto out; + } pr_debug("[server] Got CHAP_R=%s\n", chap_r); - chap_string_to_hex(client_digest, chap_r, strlen(chap_r)); tfm = crypto_alloc_shash("md5", 0, 0); if (IS_ERR(tfm)) { @@ -294,7 +280,7 @@ static int chap_server_compute_md5( goto out; } - chap_binaryhex_to_asciihex(response, server_digest, MD5_SIGNATURE_SIZE); + bin2hex(response, server_digest, MD5_SIGNATURE_SIZE); pr_debug("[server] MD5 Server Digest: %s\n", response); if (memcmp(server_digest, client_digest, MD5_SIGNATURE_SIZE) != 0) { @@ -349,9 +335,7 @@ static int chap_server_compute_md5( pr_err("Could not find CHAP_C.\n"); goto out; } - pr_debug("[server] Got CHAP_C=%s\n", challenge); - challenge_len = chap_string_to_hex(challenge_binhex, challenge, - strlen(challenge)); + challenge_len = DIV_ROUND_UP(strlen(challenge), 2); if (!challenge_len) { pr_err("Unable to convert incoming challenge\n"); goto out; @@ -360,6 +344,11 @@ static int chap_server_compute_md5( pr_err("CHAP_C exceeds maximum binary size of 1024 bytes\n"); goto out; } + if (hex2bin(challenge_binhex, challenge, challenge_len) < 0) { + pr_err("Malformed CHAP_C\n"); + goto out; + } + pr_debug("[server] Got CHAP_C=%s\n", challenge); /* * During mutual authentication, the CHAP_C generated by the * initiator must not match the original CHAP_C generated by @@ -413,7 +402,7 @@ static int chap_server_compute_md5( /* * Convert response from binary hex to ascii hext. */ - chap_binaryhex_to_asciihex(response, digest, MD5_SIGNATURE_SIZE); + bin2hex(response, digest, MD5_SIGNATURE_SIZE); *nr_out_len += sprintf(nr_out_ptr + *nr_out_len, "CHAP_R=0x%s", response); *nr_out_len += 1; diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index dc13afbd4c88dec2390ca8e65b3332d2f78acd73..27893d90c4efa992aadc7122b6c3ff00a478ed1f 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -310,11 +310,9 @@ static int iscsi_login_zero_tsih_s1( return -ENOMEM; } - ret = iscsi_login_set_conn_values(sess, conn, pdu->cid); - if (unlikely(ret)) { - kfree(sess); - return ret; - } + if (iscsi_login_set_conn_values(sess, conn, pdu->cid)) + goto free_sess; + sess->init_task_tag = pdu->itt; memcpy(&sess->isid, pdu->isid, 6); sess->exp_cmd_sn = be32_to_cpu(pdu->cmdsn); @@ -345,8 +343,7 @@ static int iscsi_login_zero_tsih_s1( pr_err("idr_alloc() for sess_idr failed\n"); iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, ISCSI_LOGIN_STATUS_NO_RESOURCES); - kfree(sess); - return -ENOMEM; + goto free_sess; } sess->creation_time = get_jiffies_64(); @@ -362,20 +359,28 @@ static int iscsi_login_zero_tsih_s1( ISCSI_LOGIN_STATUS_NO_RESOURCES); pr_err("Unable to allocate memory for" " struct iscsi_sess_ops.\n"); - kfree(sess); - return -ENOMEM; + goto remove_idr; } sess->se_sess = transport_init_session(TARGET_PROT_NORMAL); if (IS_ERR(sess->se_sess)) { iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, ISCSI_LOGIN_STATUS_NO_RESOURCES); - kfree(sess->sess_ops); - kfree(sess); - return -ENOMEM; + goto free_ops; } return 0; + +free_ops: + kfree(sess->sess_ops); +remove_idr: + spin_lock_bh(&sess_idr_lock); + idr_remove(&sess_idr, sess->session_index); + spin_unlock_bh(&sess_idr_lock); +free_sess: + kfree(sess); + conn->sess = NULL; + return -ENOMEM; } static int iscsi_login_zero_tsih_s2( @@ -1162,13 +1167,13 @@ void iscsi_target_login_sess_out(struct iscsi_conn *conn, ISCSI_LOGIN_STATUS_INIT_ERR); if (!zero_tsih || !conn->sess) goto old_sess_out; - if (conn->sess->se_sess) - transport_free_session(conn->sess->se_sess); - if (conn->sess->session_index != 0) { - spin_lock_bh(&sess_idr_lock); - idr_remove(&sess_idr, conn->sess->session_index); - spin_unlock_bh(&sess_idr_lock); - } + + transport_free_session(conn->sess->se_sess); + + spin_lock_bh(&sess_idr_lock); + idr_remove(&sess_idr, conn->sess->session_index); + spin_unlock_bh(&sess_idr_lock); + kfree(conn->sess->sess_ops); kfree(conn->sess); conn->sess = NULL; diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index 594d07a1e995ec87d467f4286a1d8668f2e32e3d..16e7516052a4486601241026d0e411e9731a716c 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -633,8 +633,7 @@ int iscsit_ta_authentication(struct iscsi_portal_group *tpg, u32 authentication) none = strstr(buf1, NONE); if (none) goto out; - strncat(buf1, ",", strlen(",")); - strncat(buf1, NONE, strlen(NONE)); + strlcat(buf1, "," NONE, sizeof(buf1)); if (iscsi_update_param_value(param, buf1) < 0) return -EINVAL; } diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index e8dd6da164b28550f42d4909afed480291cc29ab..84742125f77303ce7bf6539d7659a88ff52bdf81 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -904,14 +904,20 @@ struct se_device *target_find_device(int id, bool do_depend) EXPORT_SYMBOL(target_find_device); struct devices_idr_iter { + struct config_item *prev_item; int (*fn)(struct se_device *dev, void *data); void *data; }; static int target_devices_idr_iter(int id, void *p, void *data) + __must_hold(&device_mutex) { struct devices_idr_iter *iter = data; struct se_device *dev = p; + int ret; + + config_item_put(iter->prev_item); + iter->prev_item = NULL; /* * We add the device early to the idr, so it can be used @@ -922,7 +928,15 @@ static int target_devices_idr_iter(int id, void *p, void *data) if (!(dev->dev_flags & DF_CONFIGURED)) return 0; - return iter->fn(dev, iter->data); + iter->prev_item = config_item_get_unless_zero(&dev->dev_group.cg_item); + if (!iter->prev_item) + return 0; + mutex_unlock(&device_mutex); + + ret = iter->fn(dev, iter->data); + + mutex_lock(&device_mutex); + return ret; } /** @@ -936,15 +950,13 @@ static int target_devices_idr_iter(int id, void *p, void *data) int target_for_each_device(int (*fn)(struct se_device *dev, void *data), void *data) { - struct devices_idr_iter iter; + struct devices_idr_iter iter = { .fn = fn, .data = data }; int ret; - iter.fn = fn; - iter.data = data; - mutex_lock(&device_mutex); ret = idr_for_each(&devices_idr, target_devices_idr_iter, &iter); mutex_unlock(&device_mutex); + config_item_put(iter.prev_item); return ret; } diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index e6d51135d1055cb4edabf08730fccc13c39a5b77..0d0be7d8b9d643ac8e2cebe952e867c4cd45a2cb 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -317,6 +317,7 @@ void __transport_register_session( { const struct target_core_fabric_ops *tfo = se_tpg->se_tpg_tfo; unsigned char buf[PR_REG_ISID_LEN]; + unsigned long flags; se_sess->se_tpg = se_tpg; se_sess->fabric_sess_ptr = fabric_sess_ptr; @@ -353,7 +354,7 @@ void __transport_register_session( se_sess->sess_bin_isid = get_unaligned_be64(&buf[0]); } - spin_lock_irq(&se_nacl->nacl_sess_lock); + spin_lock_irqsave(&se_nacl->nacl_sess_lock, flags); /* * The se_nacl->nacl_sess pointer will be set to the * last active I_T Nexus for each struct se_node_acl. @@ -362,7 +363,7 @@ void __transport_register_session( list_add_tail(&se_sess->sess_acl_list, &se_nacl->acl_sess_list); - spin_unlock_irq(&se_nacl->nacl_sess_lock); + spin_unlock_irqrestore(&se_nacl->nacl_sess_lock, flags); } list_add_tail(&se_sess->sess_list, &se_tpg->tpg_sess_list); diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c index 99b19c496e8b6713d2939ea39acc5b1d69316384..6bb4da382edfd8589513db7db3b9bf4bc745f64b 100644 --- a/drivers/thermal/of-thermal.c +++ b/drivers/thermal/of-thermal.c @@ -396,10 +396,13 @@ static int of_thermal_set_mode(struct thermal_zone_device *tz, mutex_lock(&tz->lock); - if (mode == THERMAL_DEVICE_ENABLED) + if (mode == THERMAL_DEVICE_ENABLED) { tz->polling_delay = data->polling_delay; - else + tz->passive_delay = data->passive_delay; + } else { tz->polling_delay = 0; + tz->passive_delay = 0; + } mutex_unlock(&tz->lock); diff --git a/drivers/thermal/qcom/cx_ipeak_cdev.c b/drivers/thermal/qcom/cx_ipeak_cdev.c index 260d6ab91a73e9596dd1b9263c2817628e558a3f..2b6a4fb9df912acc3367ddb8f6ab7ae0a270c2b4 100644 --- a/drivers/thermal/qcom/cx_ipeak_cdev.c +++ b/drivers/thermal/qcom/cx_ipeak_cdev.c @@ -35,27 +35,49 @@ struct cxip_lm_cooling_device { struct thermal_cooling_device *cool_dev; char cdev_name[THERMAL_NAME_LENGTH]; void *cx_ip_reg_base; + unsigned int therm_clnt; + unsigned int *bypass_clnts; + unsigned int bypass_clnt_cnt; bool state; }; -static void cxip_lm_therm_vote_apply(void *reg_base, bool vote) +static void cxip_lm_therm_vote_apply(struct cxip_lm_cooling_device *cxip_dev, + bool vote) { - writel_relaxed(CXIP_LM_THERM_VOTE_VAL, - reg_base + - (vote ? CXIP_LM_VOTE_SET : CXIP_LM_VOTE_CLEAR)); + int vote_offset = 0, val = 0, sts_offset = 0; + + if (!cxip_dev->therm_clnt) { + vote_offset = vote ? CXIP_LM_VOTE_SET : CXIP_LM_VOTE_CLEAR; + val = CXIP_LM_THERM_VOTE_VAL; + sts_offset = CXIP_LM_VOTE_STATUS; + } else { + vote_offset = cxip_dev->therm_clnt; + val = vote ? 0x1 : 0x0; + sts_offset = vote_offset; + } - pr_debug("%s vote for cxip_lm. Agg.vote:0x%x\n", + writel_relaxed(val, cxip_dev->cx_ip_reg_base + vote_offset); + pr_debug("%s vote for cxip_lm. vote:0x%x\n", vote ? "Applied" : "Cleared", - readl_relaxed(reg_base + CXIP_LM_VOTE_STATUS)); + readl_relaxed(cxip_dev->cx_ip_reg_base + sts_offset)); } -static void cxip_lm_initialize_cxip_hw(void *reg_base) +static void cxip_lm_initialize_cxip_hw(struct cxip_lm_cooling_device *cxip_dev) { - /* Enable CXIP LM HW */ - writel_relaxed(CXIP_LM_FEATURE_EN_VAL, reg_base + CXIP_LM_FEATURE_EN); + int i = 0; /* Set CXIP LM proxy vote for clients who are not participating */ - writel_relaxed(CXIP_LM_BYPASS_VAL, reg_base + CXIP_LM_BYPASS); + if (cxip_dev->bypass_clnt_cnt) + for (i = 0; i < cxip_dev->bypass_clnt_cnt; i++) + writel_relaxed(0x1, cxip_dev->cx_ip_reg_base + + cxip_dev->bypass_clnts[i]); + else if (!cxip_dev->therm_clnt) + writel_relaxed(CXIP_LM_BYPASS_VAL, + cxip_dev->cx_ip_reg_base + CXIP_LM_BYPASS); + + /* Enable CXIP LM HW */ + writel_relaxed(CXIP_LM_FEATURE_EN_VAL, cxip_dev->cx_ip_reg_base + + CXIP_LM_FEATURE_EN); } static int cxip_lm_get_max_state(struct thermal_cooling_device *cdev, @@ -78,7 +100,7 @@ static int cxip_lm_set_cur_state(struct thermal_cooling_device *cdev, if (cxip_dev->state == state) return 0; - cxip_lm_therm_vote_apply(cxip_dev->cx_ip_reg_base, state); + cxip_lm_therm_vote_apply(cxip_dev, state); cxip_dev->state = state; return ret; @@ -117,6 +139,49 @@ static int cxip_lm_cdev_remove(struct platform_device *pdev) return 0; } +static int cxip_lm_get_devicetree_data(struct platform_device *pdev, + struct cxip_lm_cooling_device *cxip_dev, + struct device_node *np) +{ + int ret = 0; + + ret = of_property_read_u32(np, "qcom,thermal-client-offset", + &cxip_dev->therm_clnt); + if (ret) { + dev_dbg(&pdev->dev, + "error for qcom,thermal-client-offset. ret:%d\n", + ret); + cxip_dev->therm_clnt = 0; + ret = 0; + return ret; + } + + ret = of_property_count_u32_elems(np, "qcom,bypass-client-list"); + if (ret <= 0) { + dev_dbg(&pdev->dev, "Invalid number of clients err:%d\n", ret); + ret = 0; + return ret; + } + cxip_dev->bypass_clnt_cnt = ret; + + cxip_dev->bypass_clnts = devm_kcalloc(&pdev->dev, + cxip_dev->bypass_clnt_cnt, + sizeof(*cxip_dev->bypass_clnts), GFP_KERNEL); + if (!cxip_dev->bypass_clnts) + return -ENOMEM; + + ret = of_property_read_u32_array(np, "qcom,bypass-client-list", + cxip_dev->bypass_clnts, cxip_dev->bypass_clnt_cnt); + if (ret) { + dev_dbg(&pdev->dev, "bypass client list err:%d, cnt:%d\n", + ret, cxip_dev->bypass_clnt_cnt); + cxip_dev->bypass_clnt_cnt = 0; + ret = 0; + } + + return ret; +} + static int cxip_lm_cdev_probe(struct platform_device *pdev) { struct cxip_lm_cooling_device *cxip_dev = NULL; @@ -135,6 +200,10 @@ static int cxip_lm_cdev_probe(struct platform_device *pdev) if (!cxip_dev) return -ENOMEM; + ret = cxip_lm_get_devicetree_data(pdev, cxip_dev, np); + if (ret) + return ret; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, @@ -149,12 +218,11 @@ static int cxip_lm_cdev_probe(struct platform_device *pdev) return -ENOMEM; } - cxip_lm_initialize_cxip_hw(cxip_dev->cx_ip_reg_base); + cxip_lm_initialize_cxip_hw(cxip_dev); /* Set thermal vote till we get first vote from TF */ cxip_dev->state = true; - cxip_lm_therm_vote_apply(cxip_dev->cx_ip_reg_base, - cxip_dev->state); + cxip_lm_therm_vote_apply(cxip_dev, cxip_dev->state); strlcpy(cxip_dev->cdev_name, np->name, THERMAL_NAME_LENGTH); cxip_dev->cool_dev = thermal_of_cooling_device_register( diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 899e8fe5e00f512a75fe82c25b42f341eb9a338e..9e26c530d2ddb798385a2c731915e3ad336c0cd3 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -625,7 +625,7 @@ int ptm_open_peer(struct file *master, struct tty_struct *tty, int flags) if (tty->driver != ptm_driver) return -EIO; - fd = get_unused_fd_flags(0); + fd = get_unused_fd_flags(flags); if (fd < 0) { retval = fd; goto err; diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c index 20d79a6007d50bcb9457890df30c1d341899485d..070733ca94d5e7fd5eeac3b11462be64ecef95c9 100644 --- a/drivers/tty/rocket.c +++ b/drivers/tty/rocket.c @@ -1894,7 +1894,7 @@ static __init int register_PCI(int i, struct pci_dev *dev) ByteIO_t UPCIRingInd = 0; if (!dev || !pci_match_id(rocket_pci_ids, dev) || - pci_enable_device(dev)) + pci_enable_device(dev) || i >= NUM_BOARDS) return 0; rcktpt_io_addr[i] = pci_resource_start(dev, 0); diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 3015789265dd05d960ae5637d4b8ed7d0e410fb5..27c5b2b46b8dc0419a89fed9bd81b627a1d67eb5 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -260,7 +260,7 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, long rate; int ret; - if (IS_ERR(d->clk) || !old) + if (IS_ERR(d->clk)) goto out; clk_disable_unprepare(d->clk); @@ -672,6 +672,7 @@ static const struct acpi_device_id dw8250_acpi_match[] = { { "APMC0D08", 0}, { "AMD0020", 0 }, { "AMDI0020", 0 }, + { "BRCM2032", 0 }, { "HISI0031", 0 }, { }, }; diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index e0aa5f03004cc6c1754684716835acbd1f7f19b9..411b4b03457bbbd7bac5c1f2ed542e81ebda47e8 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -436,7 +436,11 @@ static irqreturn_t exar_misc_handler(int irq, void *data) struct exar8250 *priv = data; /* Clear all PCI interrupts by reading INT0. No effect on IIR */ - ioread8(priv->virt + UART_EXAR_INT0); + readb(priv->virt + UART_EXAR_INT0); + + /* Clear INT0 for Expansion Interface slave ports, too */ + if (priv->board->num_ports > 8) + readb(priv->virt + 0x2000 + UART_EXAR_INT0); return IRQ_HANDLED; } diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index be456ea27ab27985865c8dccbdf7be22a23e7b87..ecf3d631bc09f5670a1748f8b8a89c65b6ba4132 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -94,8 +94,7 @@ static const struct serial8250_config uart_config[] = { .name = "16550A", .fifo_size = 16, .tx_loadsz = 16, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | - UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, .rxtrig_bytes = {1, 4, 8, 14}, .flags = UART_CAP_FIFO, }, diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c index 933c2688dd7ea90c4a38d7f55938bfc454e9a67c..8106353ce7aa00853bcf4b051b80c1d02310fbbb 100644 --- a/drivers/tty/serial/8250/serial_cs.c +++ b/drivers/tty/serial/8250/serial_cs.c @@ -637,8 +637,10 @@ static int serial_config(struct pcmcia_device *link) (link->has_func_id) && (link->socket->pcmcia_pfc == 0) && ((link->func_id == CISTPL_FUNCID_MULTI) || - (link->func_id == CISTPL_FUNCID_SERIAL))) - pcmcia_loop_config(link, serial_check_for_multi, info); + (link->func_id == CISTPL_FUNCID_SERIAL))) { + if (pcmcia_loop_config(link, serial_check_for_multi, info)) + goto failed; + } /* * Apply any multi-port quirk. diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c index 9ac142cfc1f1b99a89cf21582472e05993664ed2..8b2b694334ec0568b1e08b07427c57388d50c0d5 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c @@ -1068,8 +1068,8 @@ static int poll_wait_key(char *obuf, struct uart_cpm_port *pinfo) /* Get the address of the host memory buffer. */ bdp = pinfo->rx_cur; - while (bdp->cbd_sc & BD_SC_EMPTY) - ; + if (bdp->cbd_sc & BD_SC_EMPTY) + return NO_POLL_CHAR; /* If the buffer address is in the CPM DPRAM, don't * convert it. @@ -1104,7 +1104,11 @@ static int cpm_get_poll_char(struct uart_port *port) poll_chars = 0; } if (poll_chars <= 0) { - poll_chars = poll_wait_key(poll_buf, pinfo); + int ret = poll_wait_key(poll_buf, pinfo); + + if (ret == NO_POLL_CHAR) + return ret; + poll_chars = ret; pollp = poll_buf; } poll_chars--; diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index ac667b47f19970c451712280c2a6d7fbbe7a5ff2..7b0a3a1688e8370d08257b735a0cd63c1d083926 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -254,7 +254,6 @@ int __init of_setup_earlycon(const struct earlycon_id *match, return -ENXIO; } port->mapbase = addr; - port->uartclk = BASE_BAUD * 16; val = of_get_flat_dt_prop(node, "reg-offset", NULL); if (val) @@ -289,6 +288,10 @@ int __init of_setup_earlycon(const struct earlycon_id *match, if (val) early_console_dev.baud = be32_to_cpu(*val); + val = of_get_flat_dt_prop(node, "clock-frequency", NULL); + if (val) + port->uartclk = be32_to_cpu(*val); + if (options) { early_console_dev.baud = simple_strtoul(options, NULL, 0); strlcpy(early_console_dev.options, options, diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 7a3db9378fa388818eddbdeb12082ac703686b9e..fd64ac2c1a748b80cef780d9076c2616787a85c2 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -983,7 +983,8 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport) struct circ_buf *ring = &sport->rx_ring; int ret, nent; int bits, baud; - struct tty_struct *tty = tty_port_tty_get(&sport->port.state->port); + struct tty_port *port = &sport->port.state->port; + struct tty_struct *tty = port->tty; struct ktermios *termios = &tty->termios; baud = tty_get_baud_rate(tty); diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 8deaf2ad8b34ac4bafeb795a5f5a8e4dc5faf345..4e827e5a52a364162055e4856305f6fec9b7fd19 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2213,6 +2213,14 @@ static int serial_imx_probe(struct platform_device *pdev) ret); return ret; } + + ret = devm_request_irq(&pdev->dev, rtsirq, imx_rtsint, 0, + dev_name(&pdev->dev), sport); + if (ret) { + dev_err(&pdev->dev, "failed to request rts irq: %d\n", + ret); + return ret; + } } else { ret = devm_request_irq(&pdev->dev, rxirq, imx_int, 0, dev_name(&pdev->dev), sport); diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c index 45b57c294d13b19b8d47f2e8b2292f68c8167485..401c983ec5f3651bc442b315566fc4dfc63ed627 100644 --- a/drivers/tty/serial/mvebu-uart.c +++ b/drivers/tty/serial/mvebu-uart.c @@ -327,8 +327,10 @@ static void mvebu_uart_set_termios(struct uart_port *port, if ((termios->c_cflag & CREAD) == 0) port->ignore_status_mask |= STAT_RX_RDY | STAT_BRK_ERR; - if (old) + if (old) { tty_termios_copy_hw(termios, old); + termios->c_cflag |= CS8; + } baud = uart_get_baud_rate(port, termios, old, 0, 460800); uart_update_timeout(port, termios->c_cflag, baud); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index de86a31d9ce776f1efd99e293abeccc4bee00bce..17fd89ae5642255361f3fe20a4faecc7cfd6e9c7 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -198,6 +198,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, { struct uart_port *uport = uart_port_check(state); unsigned long page; + unsigned long flags = 0; int retval = 0; if (uport->type == PORT_UNKNOWN) @@ -212,15 +213,18 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, * Initialise and allocate the transmit and temporary * buffer. */ - if (!state->xmit.buf) { - /* This is protected by the per port mutex */ - page = get_zeroed_page(GFP_KERNEL); - if (!page) - return -ENOMEM; + page = get_zeroed_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + uart_port_lock(state, flags); + if (!state->xmit.buf) { state->xmit.buf = (unsigned char *) page; uart_circ_clear(&state->xmit); + } else { + free_page(page); } + uart_port_unlock(uport, flags); retval = uport->ops->startup(uport); if (retval == 0) { @@ -279,6 +283,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) { struct uart_port *uport = uart_port_check(state); struct tty_port *port = &state->port; + unsigned long flags = 0; /* * Set the TTY IO error marker @@ -311,10 +316,12 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) /* * Free the transmit buffer page. */ + uart_port_lock(state, flags); if (state->xmit.buf) { free_page((unsigned long)state->xmit.buf); state->xmit.buf = NULL; } + uart_port_unlock(uport, flags); } /** diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 8bc8fe2b75f7a34cad43ac693a1faf7c4de8720d..37dba940d8980c36ada5e64ce70119f9a59e20af 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -2060,6 +2060,8 @@ static void sci_shutdown(struct uart_port *port) } #endif + if (s->rx_trigger > 1 && s->rx_fifo_timeout > 0) + del_timer_sync(&s->rx_fifo_timer); sci_free_irq(s); sci_free_dma(port); } diff --git a/drivers/tty/tty_baudrate.c b/drivers/tty/tty_baudrate.c index 5c33fd25676d59bc6453d7f4a5f4a46b2aadabf1..ebc797fc1afd30d5d96b2b4fd1f73db48f93aaaf 100644 --- a/drivers/tty/tty_baudrate.c +++ b/drivers/tty/tty_baudrate.c @@ -156,18 +156,25 @@ void tty_termios_encode_baud_rate(struct ktermios *termios, termios->c_ospeed = obaud; #ifdef BOTHER + if ((termios->c_cflag >> IBSHIFT) & CBAUD) + ibinput = 1; /* An input speed was specified */ + /* If the user asked for a precise weird speed give a precise weird answer. If they asked for a Bfoo speed they may have problems digesting non-exact replies so fuzz a bit */ - if ((termios->c_cflag & CBAUD) == BOTHER) + if ((termios->c_cflag & CBAUD) == BOTHER) { oclose = 0; + if (!ibinput) + iclose = 0; + } if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER) iclose = 0; - if ((termios->c_cflag >> IBSHIFT) & CBAUD) - ibinput = 1; /* An input speed was specified */ #endif termios->c_cflag &= ~CBAUD; +#ifdef IBSHIFT + termios->c_cflag &= ~(CBAUD << IBSHIFT); +#endif /* * Our goal is to find a close match to the standard baud rate diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 562d31073f9a2c588c62de7f0d64c570bf9fcf62..8d65b2f9ee8063b4bf7ce66e01eb53cb84006152 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1254,6 +1254,7 @@ static void tty_driver_remove_tty(struct tty_driver *driver, struct tty_struct * static int tty_reopen(struct tty_struct *tty) { struct tty_driver *driver = tty->driver; + int retval; if (driver->type == TTY_DRIVER_TYPE_PTY && driver->subtype == PTY_TYPE_MASTER) @@ -1267,10 +1268,14 @@ static int tty_reopen(struct tty_struct *tty) tty->count++; - if (!tty->ldisc) - return tty_ldisc_reinit(tty, tty->termios.c_line); + if (tty->ldisc) + return 0; - return 0; + retval = tty_ldisc_reinit(tty, tty->termios.c_line); + if (retval) + tty->count--; + + return retval; } /** diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 2d2b420598b236a9aa8a135ea16e74cf5763350f..7b34b0ddbf0e0281ec8ca723fb6469b5ac43d30f 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -32,6 +32,8 @@ #include #include +#include + #include #include #include @@ -700,6 +702,8 @@ int vt_ioctl(struct tty_struct *tty, if (vsa.console == 0 || vsa.console > MAX_NR_CONSOLES) ret = -ENXIO; else { + vsa.console = array_index_nospec(vsa.console, + MAX_NR_CONSOLES + 1); vsa.console--; console_lock(); ret = vc_allocate(vsa.console); diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index ff04b7f8549f06f5730afb1cf6334785afab9d05..41784798c789b9dd1c1bffbd80920e346ea283a3 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -841,8 +841,6 @@ int __uio_register_device(struct module *owner, if (ret) goto err_uio_dev_add_attributes; - info->uio_dev = idev; - if (info->irq && (info->irq != UIO_IRQ_CUSTOM)) { /* * Note that we deliberately don't use devm_request_irq @@ -858,6 +856,7 @@ int __uio_register_device(struct module *owner, goto err_request_irq; } + info->uio_dev = idev; return 0; err_request_irq: diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index f2f31fc16f2909720bd1fdf2b53d77a405098a9e..9f6f402470ac11df22c1bd188e5919e84794c155 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -792,20 +792,9 @@ static int acm_tty_write(struct tty_struct *tty, } if (acm->susp_count) { - if (acm->putbuffer) { - /* now to preserve order */ - usb_anchor_urb(acm->putbuffer->urb, &acm->delayed); - acm->putbuffer = NULL; - } usb_anchor_urb(wb->urb, &acm->delayed); spin_unlock_irqrestore(&acm->write_lock, flags); return count; - } else { - if (acm->putbuffer) { - /* at this point there is no good way to handle errors */ - acm_start_wb(acm, acm->putbuffer); - acm->putbuffer = NULL; - } } stat = acm_start_wb(acm, wb); @@ -816,66 +805,6 @@ static int acm_tty_write(struct tty_struct *tty, return count; } -static void acm_tty_flush_chars(struct tty_struct *tty) -{ - struct acm *acm = tty->driver_data; - struct acm_wb *cur; - int err; - unsigned long flags; - - spin_lock_irqsave(&acm->write_lock, flags); - - cur = acm->putbuffer; - if (!cur) /* nothing to do */ - goto out; - - acm->putbuffer = NULL; - err = usb_autopm_get_interface_async(acm->control); - if (err < 0) { - cur->use = 0; - acm->putbuffer = cur; - goto out; - } - - if (acm->susp_count) - usb_anchor_urb(cur->urb, &acm->delayed); - else - acm_start_wb(acm, cur); -out: - spin_unlock_irqrestore(&acm->write_lock, flags); - return; -} - -static int acm_tty_put_char(struct tty_struct *tty, unsigned char ch) -{ - struct acm *acm = tty->driver_data; - struct acm_wb *cur; - int wbn; - unsigned long flags; - -overflow: - cur = acm->putbuffer; - if (!cur) { - spin_lock_irqsave(&acm->write_lock, flags); - wbn = acm_wb_alloc(acm); - if (wbn >= 0) { - cur = &acm->wb[wbn]; - acm->putbuffer = cur; - } - spin_unlock_irqrestore(&acm->write_lock, flags); - if (!cur) - return 0; - } - - if (cur->len == acm->writesize) { - acm_tty_flush_chars(tty); - goto overflow; - } - - cur->buf[cur->len++] = ch; - return 1; -} - static int acm_tty_write_room(struct tty_struct *tty) { struct acm *acm = tty->driver_data; @@ -1598,6 +1527,7 @@ static void acm_disconnect(struct usb_interface *intf) { struct acm *acm = usb_get_intfdata(intf); struct tty_struct *tty; + int i; /* sibling interface is already cleaning up */ if (!acm) @@ -1628,6 +1558,11 @@ static void acm_disconnect(struct usb_interface *intf) tty_unregister_device(acm_tty_driver, acm->minor); + usb_free_urb(acm->ctrlurb); + for (i = 0; i < ACM_NW; i++) + usb_free_urb(acm->wb[i].urb); + for (i = 0; i < acm->rx_buflimit; i++) + usb_free_urb(acm->read_urbs[i]); acm_write_buffers_free(acm); usb_free_coherent(acm->dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); acm_read_buffers_free(acm); @@ -2000,8 +1935,6 @@ static const struct tty_operations acm_ops = { .cleanup = acm_tty_cleanup, .hangup = acm_tty_hangup, .write = acm_tty_write, - .put_char = acm_tty_put_char, - .flush_chars = acm_tty_flush_chars, .write_room = acm_tty_write_room, .ioctl = acm_tty_ioctl, .throttle = acm_tty_throttle, diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index eacc116e83da2ccf38b2640aa5b5b02b5b3621c8..ca06b20d7af9cc9567da1f243ad99935f8bc99e7 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h @@ -96,7 +96,6 @@ struct acm { unsigned long read_urbs_free; struct urb *read_urbs[ACM_NR]; struct acm_rb read_buffers[ACM_NR]; - struct acm_wb *putbuffer; /* for acm_tty_put_char() */ int rx_buflimit; spinlock_t read_lock; u8 *notification_buffer; /* to reassemble fragmented notifications */ diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index dd1bc69d17714367eb7c7e75ed515d93b90e7400..6c29f2b0e234ff52311b6b56ba2e05bfbc39c334 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -1025,7 +1025,7 @@ int usb_get_bos_descriptor(struct usb_device *dev) (struct usb_ptm_cap_descriptor *)buffer; break; case USB_CAP_TYPE_CONFIG_SUMMARY: - /* one such desc per configuration */ + /* one such desc per function */ if (!dev->bos->num_config_summary_desc) dev->bos->config_summary = (struct usb_config_summary_descriptor *)buffer; diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index ab245352f102a6bd6821a75be6840474f82e095e..76cb9b3649b4952d48b3c01a346134b7cd835e90 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1451,10 +1451,13 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb struct async *as = NULL; struct usb_ctrlrequest *dr = NULL; unsigned int u, totlen, isofrmlen; - int i, ret, is_in, num_sgs = 0, ifnum = -1; + int i, ret, num_sgs = 0, ifnum = -1; int number_of_packets = 0; unsigned int stream_id = 0; void *buf; + bool is_in; + bool allow_short = false; + bool allow_zero = false; unsigned long mask = USBDEVFS_URB_SHORT_NOT_OK | USBDEVFS_URB_BULK_CONTINUATION | USBDEVFS_URB_NO_FSBR | @@ -1488,6 +1491,8 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb u = 0; switch (uurb->type) { case USBDEVFS_URB_TYPE_CONTROL: + if (is_in) + allow_short = true; if (!usb_endpoint_xfer_control(&ep->desc)) return -EINVAL; /* min 8 byte setup packet */ @@ -1528,6 +1533,10 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb break; case USBDEVFS_URB_TYPE_BULK: + if (!is_in) + allow_zero = true; + else + allow_short = true; switch (usb_endpoint_type(&ep->desc)) { case USB_ENDPOINT_XFER_CONTROL: case USB_ENDPOINT_XFER_ISOC: @@ -1548,6 +1557,10 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb if (!usb_endpoint_xfer_int(&ep->desc)) return -EINVAL; interrupt_urb: + if (!is_in) + allow_zero = true; + else + allow_short = true; break; case USBDEVFS_URB_TYPE_ISO: @@ -1692,16 +1705,21 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb u = (is_in ? URB_DIR_IN : URB_DIR_OUT); if (uurb->flags & USBDEVFS_URB_ISO_ASAP) u |= URB_ISO_ASAP; - if (uurb->flags & USBDEVFS_URB_SHORT_NOT_OK && is_in) + if (allow_short && uurb->flags & USBDEVFS_URB_SHORT_NOT_OK) u |= URB_SHORT_NOT_OK; if (uurb->flags & USBDEVFS_URB_NO_FSBR) u |= URB_NO_FSBR; - if (uurb->flags & USBDEVFS_URB_ZERO_PACKET) + if (allow_zero && uurb->flags & USBDEVFS_URB_ZERO_PACKET) u |= URB_ZERO_PACKET; if (uurb->flags & USBDEVFS_URB_NO_INTERRUPT) u |= URB_NO_INTERRUPT; as->urb->transfer_flags = u; + if (!allow_short && uurb->flags & USBDEVFS_URB_SHORT_NOT_OK) + dev_warn(&ps->dev->dev, "Requested nonsensical USBDEVFS_URB_SHORT_NOT_OK.\n"); + if (!allow_zero && uurb->flags & USBDEVFS_URB_ZERO_PACKET) + dev_warn(&ps->dev->dev, "Requested nonsensical USBDEVFS_URB_ZERO_PACKET.\n"); + as->urb->transfer_buffer_length = uurb->buffer_length; as->urb->setup_packet = (unsigned char *)dr; dr = NULL; diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index becbd6173f5ad9d9aebd1518a3f98ee0d4bb4069..6a0a20ef5043829283f26084f95b135b12deb6ce 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -512,7 +512,6 @@ int usb_driver_claim_interface(struct usb_driver *driver, struct device *dev; struct usb_device *udev; int retval = 0; - int lpm_disable_error = -ENODEV; if (!iface) return -ENODEV; @@ -533,16 +532,6 @@ int usb_driver_claim_interface(struct usb_driver *driver, iface->condition = USB_INTERFACE_BOUND; - /* See the comment about disabling LPM in usb_probe_interface(). */ - if (driver->disable_hub_initiated_lpm) { - lpm_disable_error = usb_unlocked_disable_lpm(udev); - if (lpm_disable_error) { - dev_err(&iface->dev, "%s Failed to disable LPM for driver %s\n.", - __func__, driver->name); - return -ENOMEM; - } - } - /* Claimed interfaces are initially inactive (suspended) and * runtime-PM-enabled, but only if the driver has autosuspend * support. Otherwise they are marked active, to prevent the @@ -561,9 +550,20 @@ int usb_driver_claim_interface(struct usb_driver *driver, if (device_is_registered(dev)) retval = device_bind_driver(dev); - /* Attempt to re-enable USB3 LPM, if the disable was successful. */ - if (!lpm_disable_error) - usb_unlocked_enable_lpm(udev); + if (retval) { + dev->driver = NULL; + usb_set_intfdata(iface, NULL); + iface->needs_remote_wakeup = 0; + iface->condition = USB_INTERFACE_UNBOUND; + + /* + * Unbound interfaces are always runtime-PM-disabled + * and runtime-PM-suspended + */ + if (driver->supports_autosuspend) + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + } return retval; } diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 644a4989a4ae1a6e42e8dba018229511212ad8da..041c7c4cb20ba413fee9b2c4e8eacec47d4bc9d7 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -44,30 +44,33 @@ static int is_activesync(struct usb_interface_descriptor *desc) && desc->bInterfaceProtocol == 1; } -static int usb_audio_max_rev_config(struct usb_host_bos *bos) +static int get_usb_audio_config(struct usb_host_bos *bos) { - int desc_cnt, func_cnt, numfunc; - int num_cfg_desc; + unsigned int desc_cnt, num_cfg_desc, len = 0; + unsigned char *buffer; struct usb_config_summary_descriptor *conf_summary; if (!bos || !bos->config_summary) goto done; - conf_summary = bos->config_summary; num_cfg_desc = bos->num_config_summary_desc; - + conf_summary = bos->config_summary; + buffer = (unsigned char *)conf_summary; for (desc_cnt = 0; desc_cnt < num_cfg_desc; desc_cnt++) { - numfunc = conf_summary->bNumFunctions; - for (func_cnt = 0; func_cnt < numfunc; func_cnt++) { - /* look for BADD 3.0 */ - if (conf_summary->cs_info[func_cnt].bClass == - USB_CLASS_AUDIO && - conf_summary->cs_info[func_cnt].bProtocol == - UAC_VERSION_3 && - conf_summary->cs_info[func_cnt].bSubClass != - FULL_ADC_PROFILE) - return conf_summary->bConfigurationValue; - } + conf_summary = + (struct usb_config_summary_descriptor *)(buffer + len); + + len += conf_summary->bLength; + + if (conf_summary->bcdVersion != USB_CONFIG_SUMMARY_DESC_REV || + conf_summary->bClass != USB_CLASS_AUDIO) + continue; + + /* look for 1st config summary without UAC3 full ADC profile */ + if (conf_summary->bProtocol < UAC_VERSION_3 || + (conf_summary->bProtocol == UAC_VERSION_3 && + conf_summary->bSubClass != FULL_ADC_PROFILE)) + return conf_summary->bConfigurationIndex[0]; } done: @@ -176,8 +179,8 @@ int usb_choose_configuration(struct usb_device *udev) insufficient_power, plural(insufficient_power)); if (best) { - /* choose usb audio class preferred config if available */ - i = usb_audio_max_rev_config(udev->bos); + /* choose device preferred config */ + i = get_usb_audio_config(udev->bos); if (i < 0) i = best->desc.bConfigurationValue; dev_dbg(&udev->dev, diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index ea829ad798c0773c7ea93ec0dbeda5ff1772f6ba..5340d433cdf0ebc1bdc0d47fe312763a539bc06a 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -528,8 +528,6 @@ static int resume_common(struct device *dev, int event) event == PM_EVENT_RESTORE); if (retval) { dev_err(dev, "PCI post-resume error %d!\n", retval); - if (hcd->shared_hcd) - usb_hc_died(hcd->shared_hcd); usb_hc_died(hcd); } } diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index dd29e6ec1c437d5c691fa6b9dc5cc64a2be0778c..833ddd228e3a80cc150a484cc683a567df48a62e 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1280,6 +1280,11 @@ void usb_enable_interface(struct usb_device *dev, * is submitted that needs that bandwidth. Some other operating systems * allocate bandwidth early, when a configuration is chosen. * + * xHCI reserves bandwidth and configures the alternate setting in + * usb_hcd_alloc_bandwidth(). If it fails the original interface altsetting + * may be disabled. Drivers cannot rely on any particular alternate + * setting being in effect after a failure. + * * This call is synchronous, and may not be used in an interrupt context. * Also, drivers must not change altsettings while urbs are scheduled for * endpoints in that interface; all such urbs must first be completed @@ -1315,6 +1320,12 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) alternate); return -EINVAL; } + /* + * usb3 hosts configure the interface in usb_hcd_alloc_bandwidth, + * including freeing dropped endpoint ring buffers. + * Make sure the interface endpoints are flushed before that + */ + usb_disable_interface(dev, iface, false); /* Make sure we have enough bandwidth for this alternate interface. * Remove the current alt setting and add the new alt setting. diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 99f67764765fdc23bf78051c4c72d914eb64f3b6..37a5e07b3488de2173574dbd757ff1520a2e9332 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -37,6 +37,10 @@ static const struct usb_device_id usb_quirk_list[] = { /* CBM - Flash disk */ { USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME }, + /* WORLDE Controller KS49 or Prodipe MIDI 49C USB controller */ + { USB_DEVICE(0x0218, 0x0201), .driver_info = + USB_QUIRK_CONFIG_INTF_STRINGS }, + /* WORLDE easy key (easykey.25) MIDI controller */ { USB_DEVICE(0x0218, 0x0401), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, @@ -259,6 +263,9 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x2040, 0x7200), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, + /* DJI CineSSD */ + { USB_DEVICE(0x2ca3, 0x0031), .driver_info = USB_QUIRK_NO_LPM }, + /* INTEL VALUE SSD */ { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME }, diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 70990b91ea3960f7211e2e4d30bf498308fc6927..c63bf226ed5bd8296519cf15b7090ab656768362 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -228,6 +228,8 @@ struct usb_host_interface *usb_find_alt_setting( struct usb_interface_cache *intf_cache = NULL; int i; + if (!config) + return NULL; for (i = 0; i < config->desc.bNumInterfaces; i++) { if (config->intf_cache[i]->altsetting[0].desc.bInterfaceNumber == iface_num) { diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index ec965ac5f1f5dfb4ae87f1f8ee830542e436c455..3c0d386dc62fcda61b77e70357aedd464bb640fa 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -872,6 +872,7 @@ struct dwc2_hregs_backup { * @frame_list_sz: Frame list size * @desc_gen_cache: Kmem cache for generic descriptors * @desc_hsisoc_cache: Kmem cache for hs isochronous descriptors + * @unaligned_cache: Kmem cache for DMA mode to handle non-aligned buf * * These are for peripheral mode: * @@ -1004,6 +1005,8 @@ struct dwc2_hsotg { u32 frame_list_sz; struct kmem_cache *desc_gen_cache; struct kmem_cache *desc_hsisoc_cache; + struct kmem_cache *unaligned_cache; +#define DWC2_KMEM_UNALIGNED_BUF_SIZE 1024 #ifdef DEBUG u32 frrem_samples; diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 6ef001a83fe28bf0320d322dcc4867304c070055..e164439b215429492ce414bd8d088109397ea639 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -848,6 +848,7 @@ static int dwc2_gadget_fill_isoc_desc(struct dwc2_hsotg_ep *hs_ep, u32 index; u32 maxsize = 0; u32 mask = 0; + u8 pid = 0; maxsize = dwc2_gadget_get_desc_params(hs_ep, &mask); if (len > maxsize) { @@ -893,7 +894,11 @@ static int dwc2_gadget_fill_isoc_desc(struct dwc2_hsotg_ep *hs_ep, ((len << DEV_DMA_NBYTES_SHIFT) & mask)); if (hs_ep->dir_in) { - desc->status |= ((hs_ep->mc << DEV_DMA_ISOC_PID_SHIFT) & + if (len) + pid = DIV_ROUND_UP(len, hs_ep->ep.maxpacket); + else + pid = 1; + desc->status |= ((pid << DEV_DMA_ISOC_PID_SHIFT) & DEV_DMA_ISOC_PID_MASK) | ((len % hs_ep->ep.maxpacket) ? DEV_DMA_SHORT : 0) | @@ -932,6 +937,7 @@ static void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep *hs_ep) u32 ctrl; if (list_empty(&hs_ep->queue)) { + hs_ep->target_frame = TARGET_FRAME_INITIAL; dev_dbg(hsotg->dev, "%s: No requests in queue\n", __func__); return; } @@ -4716,9 +4722,11 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) } ret = usb_add_gadget_udc(dev, &hsotg->gadget); - if (ret) + if (ret) { + dwc2_hsotg_ep_free_request(&hsotg->eps_out[0]->ep, + hsotg->ctrl_req); return ret; - + } dwc2_hsotg_dump(hsotg); return 0; @@ -4731,6 +4739,7 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) int dwc2_hsotg_remove(struct dwc2_hsotg *hsotg) { usb_del_gadget_udc(&hsotg->gadget); + dwc2_hsotg_ep_free_request(&hsotg->eps_out[0]->ep, hsotg->ctrl_req); return 0; } diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 46d3b0fc00c5c6dadc91d61d3bcfeb3571697449..fa20ec43a187673e7461d408d55b725bcfc611eb 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -1544,11 +1544,20 @@ static void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg, } if (hsotg->params.host_dma) { - dwc2_writel((u32)chan->xfer_dma, - hsotg->regs + HCDMA(chan->hc_num)); + dma_addr_t dma_addr; + + if (chan->align_buf) { + if (dbg_hc(chan)) + dev_vdbg(hsotg->dev, "align_buf\n"); + dma_addr = chan->align_buf; + } else { + dma_addr = chan->xfer_dma; + } + dwc2_writel((u32)dma_addr, hsotg->regs + HCDMA(chan->hc_num)); + if (dbg_hc(chan)) dev_vdbg(hsotg->dev, "Wrote %08lx to HCDMA(%d)\n", - (unsigned long)chan->xfer_dma, chan->hc_num); + (unsigned long)dma_addr, chan->hc_num); } /* Start the split */ @@ -2604,6 +2613,35 @@ static void dwc2_hc_init_xfer(struct dwc2_hsotg *hsotg, } } +static int dwc2_alloc_split_dma_aligned_buf(struct dwc2_hsotg *hsotg, + struct dwc2_qh *qh, + struct dwc2_host_chan *chan) +{ + if (!hsotg->unaligned_cache || + chan->max_packet > DWC2_KMEM_UNALIGNED_BUF_SIZE) + return -ENOMEM; + + if (!qh->dw_align_buf) { + qh->dw_align_buf = kmem_cache_alloc(hsotg->unaligned_cache, + GFP_ATOMIC | GFP_DMA); + if (!qh->dw_align_buf) + return -ENOMEM; + } + + qh->dw_align_buf_dma = dma_map_single(hsotg->dev, qh->dw_align_buf, + DWC2_KMEM_UNALIGNED_BUF_SIZE, + DMA_FROM_DEVICE); + + if (dma_mapping_error(hsotg->dev, qh->dw_align_buf_dma)) { + dev_err(hsotg->dev, "can't map align_buf\n"); + chan->align_buf = 0; + return -EINVAL; + } + + chan->align_buf = qh->dw_align_buf_dma; + return 0; +} + #define DWC2_USB_DMA_ALIGN 4 static void dwc2_free_dma_aligned_buffer(struct urb *urb) @@ -2783,6 +2821,32 @@ static int dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) /* Set the transfer attributes */ dwc2_hc_init_xfer(hsotg, chan, qtd); + /* For non-dword aligned buffers */ + if (hsotg->params.host_dma && qh->do_split && + chan->ep_is_in && (chan->xfer_dma & 0x3)) { + dev_vdbg(hsotg->dev, "Non-aligned buffer\n"); + if (dwc2_alloc_split_dma_aligned_buf(hsotg, qh, chan)) { + dev_err(hsotg->dev, + "Failed to allocate memory to handle non-aligned buffer\n"); + /* Add channel back to free list */ + chan->align_buf = 0; + chan->multi_count = 0; + list_add_tail(&chan->hc_list_entry, + &hsotg->free_hc_list); + qtd->in_process = 0; + qh->channel = NULL; + return -ENOMEM; + } + } else { + /* + * We assume that DMA is always aligned in non-split + * case or split out case. Warn if not. + */ + WARN_ON_ONCE(hsotg->params.host_dma && + (chan->xfer_dma & 0x3)); + chan->align_buf = 0; + } + if (chan->ep_type == USB_ENDPOINT_XFER_INT || chan->ep_type == USB_ENDPOINT_XFER_ISOC) /* @@ -5277,6 +5341,19 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg) } } + if (hsotg->params.host_dma) { + /* + * Create kmem caches to handle non-aligned buffer + * in Buffer DMA mode. + */ + hsotg->unaligned_cache = kmem_cache_create("dwc2-unaligned-dma", + DWC2_KMEM_UNALIGNED_BUF_SIZE, 4, + SLAB_CACHE_DMA, NULL); + if (!hsotg->unaligned_cache) + dev_err(hsotg->dev, + "unable to create dwc2 unaligned cache\n"); + } + hsotg->otg_port = 1; hsotg->frame_list = NULL; hsotg->frame_list_dma = 0; @@ -5311,8 +5388,9 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg) return 0; error4: - kmem_cache_destroy(hsotg->desc_gen_cache); + kmem_cache_destroy(hsotg->unaligned_cache); kmem_cache_destroy(hsotg->desc_hsisoc_cache); + kmem_cache_destroy(hsotg->desc_gen_cache); error3: dwc2_hcd_release(hsotg); error2: @@ -5353,8 +5431,9 @@ void dwc2_hcd_remove(struct dwc2_hsotg *hsotg) usb_remove_hcd(hcd); hsotg->priv = NULL; - kmem_cache_destroy(hsotg->desc_gen_cache); + kmem_cache_destroy(hsotg->unaligned_cache); kmem_cache_destroy(hsotg->desc_hsisoc_cache); + kmem_cache_destroy(hsotg->desc_gen_cache); dwc2_hcd_release(hsotg); usb_put_hcd(hcd); diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h index 11c3c145b79363d673b4db83be09076ac38095ee..461bdc67df6fbb244e6c1cd492fa3be5db9aff96 100644 --- a/drivers/usb/dwc2/hcd.h +++ b/drivers/usb/dwc2/hcd.h @@ -75,6 +75,8 @@ struct dwc2_qh; * (micro)frame * @xfer_buf: Pointer to current transfer buffer position * @xfer_dma: DMA address of xfer_buf + * @align_buf: In Buffer DMA mode this will be used if xfer_buf is not + * DWORD aligned * @xfer_len: Total number of bytes to transfer * @xfer_count: Number of bytes transferred so far * @start_pkt_count: Packet count at start of transfer @@ -132,6 +134,7 @@ struct dwc2_host_chan { u8 *xfer_buf; dma_addr_t xfer_dma; + dma_addr_t align_buf; u32 xfer_len; u32 xfer_count; u16 start_pkt_count; @@ -302,6 +305,9 @@ struct dwc2_hs_transfer_time { * is tightly packed. * @ls_duration_us: Duration on the low speed bus schedule. * @ntd: Actual number of transfer descriptors in a list + * @dw_align_buf: Used instead of original buffer if its physical address + * is not dword-aligned + * @dw_align_buf_dma: DMA address for dw_align_buf * @qtd_list: List of QTDs for this QH * @channel: Host channel currently processing transfers for this QH * @qh_list_entry: Entry for QH in either the periodic or non-periodic @@ -345,6 +351,8 @@ struct dwc2_qh { struct dwc2_hs_transfer_time hs_transfers[DWC2_HS_SCHEDULE_UFRAMES]; u32 ls_start_schedule_slice; u16 ntd; + u8 *dw_align_buf; + dma_addr_t dw_align_buf_dma; struct list_head qtd_list; struct dwc2_host_chan *channel; struct list_head qh_list_entry; diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c index 28a8210710b121616353d881b2e27c73da7e03da..17905ba1139c5698a9a72b0ef4cf2c8a67f55291 100644 --- a/drivers/usb/dwc2/hcd_intr.c +++ b/drivers/usb/dwc2/hcd_intr.c @@ -923,14 +923,21 @@ static int dwc2_xfercomp_isoc_split_in(struct dwc2_hsotg *hsotg, frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index]; len = dwc2_get_actual_xfer_length(hsotg, chan, chnum, qtd, DWC2_HC_XFER_COMPLETE, NULL); - if (!len) { + if (!len && !qtd->isoc_split_offset) { qtd->complete_split = 0; - qtd->isoc_split_offset = 0; return 0; } frame_desc->actual_length += len; + if (chan->align_buf) { + dev_vdbg(hsotg->dev, "non-aligned buffer\n"); + dma_unmap_single(hsotg->dev, chan->qh->dw_align_buf_dma, + DWC2_KMEM_UNALIGNED_BUF_SIZE, DMA_FROM_DEVICE); + memcpy(qtd->urb->buf + (chan->xfer_dma - qtd->urb->dma), + chan->qh->dw_align_buf, len); + } + qtd->isoc_split_offset += len; hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum)); diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c index 7f51a77bc5ccd3335277a474f27c6e143b58df0f..56e61220efc66a5571159ca2f46932576ab451dd 100644 --- a/drivers/usb/dwc2/hcd_queue.c +++ b/drivers/usb/dwc2/hcd_queue.c @@ -1632,6 +1632,9 @@ void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) if (qh->desc_list) dwc2_hcd_qh_free_ddma(hsotg, qh); + else if (hsotg->unaligned_cache && qh->dw_align_buf) + kmem_cache_free(hsotg->unaligned_cache, qh->dw_align_buf); + kfree(qh); } diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 7f131e901d7d791859543e765aa9c58b465ce616..e9490e367148bb456ef437dd81a02bb04ccf14fc 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -519,6 +519,22 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc) parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8); } +static int dwc3_core_ulpi_init(struct dwc3 *dwc) +{ + int intf; + int ret = 0; + + intf = DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3); + + if (intf == DWC3_GHWPARAMS3_HSPHY_IFC_ULPI || + (intf == DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI && + dwc->hsphy_interface && + !strncmp(dwc->hsphy_interface, "ulpi", 4))) + ret = dwc3_ulpi_init(dwc); + + return ret; +} + /** * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core * @dwc: Pointer to our controller context structure @@ -530,7 +546,6 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc) static int dwc3_phy_setup(struct dwc3 *dwc) { u32 reg; - int ret; reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); @@ -605,9 +620,6 @@ static int dwc3_phy_setup(struct dwc3 *dwc) } /* FALLTHROUGH */ case DWC3_GHWPARAMS3_HSPHY_IFC_ULPI: - ret = dwc3_ulpi_init(dwc); - if (ret) - return ret; /* FALLTHROUGH */ default: break; @@ -768,6 +780,7 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc) } static int dwc3_core_get_phy(struct dwc3 *dwc); +static int dwc3_core_ulpi_init(struct dwc3 *dwc); /** * dwc3_core_init - Low-level initialization of DWC3 Core @@ -807,17 +820,27 @@ int dwc3_core_init(struct dwc3 *dwc) dwc->maximum_speed = USB_SPEED_HIGH; } - ret = dwc3_core_get_phy(dwc); + ret = dwc3_phy_setup(dwc); if (ret) goto err0; - ret = dwc3_core_soft_reset(dwc); - if (ret) - goto err0; + if (!dwc->ulpi_ready) { + ret = dwc3_core_ulpi_init(dwc); + if (ret) + goto err0; + dwc->ulpi_ready = true; + } - ret = dwc3_phy_setup(dwc); + if (!dwc->phys_ready) { + ret = dwc3_core_get_phy(dwc); + if (ret) + goto err0a; + dwc->phys_ready = true; + } + + ret = dwc3_core_soft_reset(dwc); if (ret) - goto err0; + goto err0a; dwc3_core_setup_global_control(dwc); dwc3_core_num_eps(dwc); @@ -926,6 +949,9 @@ int dwc3_core_init(struct dwc3 *dwc) phy_exit(dwc->usb2_generic_phy); phy_exit(dwc->usb3_generic_phy); +err0a: + dwc3_ulpi_exit(dwc); + err0: return ret; } diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index fb6cd97214a32cb6a7deabf718dea4fe8e3e7c76..f608a270dc375dd617bb4bc0edfe2cb0f04ea3ef 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -902,7 +902,9 @@ struct dwc3_scratchpad_array { * @usb3_phy: pointer to USB3 PHY * @usb2_generic_phy: pointer to USB2 PHY * @usb3_generic_phy: pointer to USB3 PHY + * @phys_ready: flag to indicate that PHYs are ready * @ulpi: pointer to ulpi interface + * @ulpi_ready: flag to indicate that ULPI is initialized * @isoch_delay: wValue from Set Isochronous Delay request; * @u2sel: parameter from Set SEL request. * @u2pel: parameter from Set SEL request. @@ -1021,7 +1023,10 @@ struct dwc3 { struct phy *usb2_generic_phy; struct phy *usb3_generic_phy; + bool phys_ready; + struct ulpi *ulpi; + bool ulpi_ready; void __iomem *regs; size_t regs_size; diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 5123b3954d9d64854f9f2130b282a17efa66516f..303506bc1f3f4e16364534d91744b8ac7672b3d7 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -381,34 +381,9 @@ static inline void dwc3_msm_write_reg_field(void __iomem *base, u32 offset, tmp &= ~mask; /* clear written bits */ val = tmp | (val << shift); iowrite32(val, base + offset); -} -/** - * Write register and read back masked value to confirm it is written - * - * @base - DWC3 base virtual address. - * @offset - register offset. - * @mask - register bitmask specifying what should be updated - * @val - value to write. - * - */ -static inline void dwc3_msm_write_readback(void __iomem *base, u32 offset, - const u32 mask, u32 val) -{ - u32 write_val, tmp = ioread32(base + offset); - - tmp &= ~mask; /* retain other bits */ - write_val = tmp | val; - - iowrite32(write_val, base + offset); - - /* Read back to see if val was written */ - tmp = ioread32(base + offset); - tmp &= mask; /* clear other bits */ - - if (tmp != val) - pr_err("%s: write: %x to QSCRATCH: %x FAILED\n", - __func__, val, offset); + /* Read back to make sure that previous write goes through */ + ioread32(base + offset); } static bool dwc3_msm_is_ss_rhport_connected(struct dwc3_msm *mdwc) @@ -3675,13 +3650,15 @@ static int dwc3_msm_probe(struct platform_device *pdev) if (ret) goto put_dwc3; } else { - if (dwc->dr_mode == USB_DR_MODE_OTG || - dwc->dr_mode == USB_DR_MODE_PERIPHERAL) { - dev_dbg(mdwc->dev, "%s: no extcon, simulate vbus connect\n", + if ((dwc->dr_mode == USB_DR_MODE_OTG && + !of_property_read_bool(node, "qcom,default-mode-host")) || + dwc->dr_mode == USB_DR_MODE_PERIPHERAL) { + dev_dbg(mdwc->dev, "%s: no extcon, start peripheral mode\n", __func__); mdwc->vbus_active = true; - } else if (dwc->dr_mode == USB_DR_MODE_HOST) { - dev_dbg(mdwc->dev, "DWC3 in host only mode\n"); + } else { + dev_dbg(mdwc->dev, "%s: no extcon, start host mode\n", + __func__); mdwc->id_state = DWC3_ID_GROUND; } @@ -4050,17 +4027,14 @@ static void dwc3_override_vbus_status(struct dwc3_msm *mdwc, bool vbus_present) struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); /* Update OTG VBUS Valid from HSPHY to controller */ - dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, - vbus_present ? UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL : - UTMI_OTG_VBUS_VALID, - vbus_present ? UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL : 0); + dwc3_msm_write_reg_field(mdwc->base, HS_PHY_CTRL_REG, + UTMI_OTG_VBUS_VALID, !!vbus_present); /* Update only if Super Speed is supported */ if (dwc->maximum_speed >= USB_SPEED_SUPER) { /* Update VBUS Valid from SSPHY to controller */ - dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, - LANE0_PWR_PRESENT, - vbus_present ? LANE0_PWR_PRESENT : 0); + dwc3_msm_write_reg_field(mdwc->base, SS_PHY_CTRL_REG, + LANE0_PWR_PRESENT, !!vbus_present); } } @@ -4162,7 +4136,7 @@ static int dwc3_usb_blocking_sync(struct notifier_block *nb, dbg_event(0xFF, "fw_blocksync", 0); flush_work(&mdwc->resume_work); - flush_delayed_work(&mdwc->sm_work); + drain_workqueue(mdwc->sm_usb_wq); if (!mdwc->in_host_mode && !mdwc->in_device_mode) { dbg_event(0xFF, "lpm_state", atomic_read(&dwc->in_lpm)); diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c index d40ad0576a299693592a28e4144e239d71ca04f8..b0a78d57f1e0728cf18d9fe98b476d78bce49d3e 100644 --- a/drivers/usb/dwc3/dwc3-of-simple.c +++ b/drivers/usb/dwc3/dwc3-of-simple.c @@ -148,8 +148,9 @@ static int dwc3_of_simple_remove(struct platform_device *pdev) of_platform_depopulate(dev); - pm_runtime_put_sync(dev); pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); + pm_runtime_set_suspended(dev); return 0; } diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index bc5e91d4fac87c80d184fccd24267467666d0dd3..09c0454833ad20cdde3e940b51eac9a1448d8815 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -41,6 +41,7 @@ #define PCI_DEVICE_ID_INTEL_GLK 0x31aa #define PCI_DEVICE_ID_INTEL_CNPLP 0x9dee #define PCI_DEVICE_ID_INTEL_CNPH 0xa36e +#define PCI_DEVICE_ID_INTEL_ICLLP 0x34ee #define PCI_INTEL_BXT_DSM_GUID "732b85d5-b7a7-4a1b-9ba0-4bbd00ffd511" #define PCI_INTEL_BXT_FUNC_PMU_PWR 4 @@ -273,6 +274,7 @@ static const struct pci_device_id dwc3_pci_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GLK), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CNPLP), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CNPH), }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICLLP), }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), }, { } /* Terminating Entry */ }; diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index 6406fc4b99071925ea6787cef814e4e98520dbdc..2f22d74c5309d9e5c3cedffee753480bd4d60bfa 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -33,7 +33,7 @@ struct dwc3; #define DWC3_DEPCFG_XFER_IN_PROGRESS_EN BIT(9) #define DWC3_DEPCFG_XFER_NOT_READY_EN BIT(10) #define DWC3_DEPCFG_FIFO_ERROR_EN BIT(11) -#define DWC3_DEPCFG_STREAM_EVENT_EN BIT(12) +#define DWC3_DEPCFG_STREAM_EVENT_EN BIT(13) #define DWC3_DEPCFG_BINTERVAL_M1(n) (((n) & 0xff) << 16) #define DWC3_DEPCFG_STREAM_CAPABLE BIT(24) #define DWC3_DEPCFG_EP_NUMBER(n) (((n) & 0x1f) << 25) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 4df3b587a3777e701676a9b67b552decb323ba67..5e83dd319efdd1e1b44b03cb9e8c94f0dd0a3b72 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1856,6 +1856,8 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) */ if (w_value && !f->get_alt) break; + + spin_lock(&cdev->lock); value = f->set_alt(f, w_index, w_value); if (value == USB_GADGET_DELAYED_STATUS) { DBG(cdev, @@ -1865,6 +1867,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) DBG(cdev, "delayed_status count %d\n", cdev->delayed_status); } + spin_unlock(&cdev->lock); break; case USB_REQ_GET_INTERFACE: if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) @@ -2461,7 +2464,13 @@ void composite_resume(struct usb_gadget *gadget) f->func_wakeup_pending = 0; } - if (gadget->speed != USB_SPEED_SUPER && f->resume) + /* + * Call function resume irrespective of the speed. + * Individual function needs to retain the USB3 Function + * suspend state through out the Device suspend entry + * and exit process. + */ + if (f->resume) f->resume(f); } diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index d25bb0cebd44789defe8e40c9b2ab601cc7a2801..457da74660b646701b5f5a72a947af4b793e9f12 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -230,6 +230,7 @@ struct ffs_io_data { struct mm_struct *mm; struct work_struct work; + struct work_struct cancellation_work; struct usb_ep *ep; struct usb_request *req; @@ -1156,25 +1157,34 @@ ffs_epfile_open(struct inode *inode, struct file *file) return 0; } +static void ffs_aio_cancel_worker(struct work_struct *work) +{ + struct ffs_io_data *io_data = container_of(work, struct ffs_io_data, + cancellation_work); + + ENTER(); + + usb_ep_dequeue(io_data->ep, io_data->req); +} + static int ffs_aio_cancel(struct kiocb *kiocb) { struct ffs_io_data *io_data = kiocb->private; - struct ffs_epfile *epfile = kiocb->ki_filp->private_data; + struct ffs_data *ffs = io_data->ffs; int value; ENTER(); - ffs_log("enter:state %d setup_state %d flag %lu", epfile->ffs->state, - epfile->ffs->setup_state, epfile->ffs->flags); - - spin_lock_irq(&epfile->ffs->eps_lock); + ffs_log("enter:state %d setup_state %d flag %lu", ffs->state, + ffs->setup_state, ffs->flags); - if (likely(io_data && io_data->ep && io_data->req)) - value = usb_ep_dequeue(io_data->ep, io_data->req); - else + if (likely(io_data && io_data->ep && io_data->req)) { + INIT_WORK(&io_data->cancellation_work, ffs_aio_cancel_worker); + queue_work(ffs->io_completion_wq, &io_data->cancellation_work); + value = -EINPROGRESS; + } else { value = -EINVAL; - - spin_unlock_irq(&epfile->ffs->eps_lock); + } ffs_log("exit: value %d", value); diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index aa957beed1c5721280465d4aecb423633a3c138c..f7cf4bfdac5f3519a69023940247fc51cfbc9dc4 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -15,6 +15,12 @@ #include "f_gsi.h" #include "rndis.h" +struct usb_gsi_debugfs { + struct dentry *debugfs_root; +}; + +static struct usb_gsi_debugfs debugfs; + static bool qti_packet_debug; module_param(qti_packet_debug, bool, 0644); MODULE_PARM_DESC(qti_packet_debug, "Print QTI Packet's Raw Data"); @@ -47,7 +53,7 @@ static inline bool usb_gsi_remote_wakeup_allowed(struct usb_function *f) bool remote_wakeup_allowed; struct f_gsi *gsi = func_to_gsi(f); - if (f->config->cdev->gadget->speed == USB_SPEED_SUPER) + if (f->config->cdev->gadget->speed >= USB_SPEED_SUPER) remote_wakeup_allowed = f->func_wakeup_allowed; else remote_wakeup_allowed = f->config->cdev->gadget->remote_wakeup; @@ -166,7 +172,7 @@ static int gsi_wakeup_host(struct f_gsi *gsi) * allowed to do so by the host. This is done in order to support non * fully USB 3.0 compatible hosts. */ - if ((gadget->speed == USB_SPEED_SUPER) && (func->func_is_suspended)) { + if ((gadget->speed >= USB_SPEED_SUPER) && (func->func_is_suspended)) { log_event_dbg("%s: Calling usb_func_wakeup", __func__); ret = usb_func_wakeup(func); } else { @@ -182,6 +188,212 @@ static int gsi_wakeup_host(struct f_gsi *gsi) return ret; } +static void gsi_rw_timer_func(unsigned long arg) +{ + struct f_gsi *gsi = (struct f_gsi *)arg; + + if (!atomic_read(&gsi->connected)) { + log_event_dbg("%s: gsi not connected.. bail-out\n", __func__); + gsi->debugfs_rw_timer_enable = 0; + return; + } + + log_event_dbg("%s: calling gsi_wakeup_host\n", __func__); + gsi_wakeup_host(gsi); + + if (gsi->debugfs_rw_timer_enable) { + log_event_dbg("%s: re-arm the timer\n", __func__); + mod_timer(&gsi->gsi_rw_timer, + jiffies + msecs_to_jiffies(gsi->gsi_rw_timer_interval)); + } +} + +static struct f_gsi *get_connected_gsi(void) +{ + struct f_gsi *connected_gsi; + bool gsi_connected = false; + int i; + + for (i = 0; i < IPA_USB_MAX_TETH_PROT_SIZE; i++) { + if (inst_status[i].opts) + connected_gsi = inst_status[i].opts->gsi; + else + continue; + + if (connected_gsi && atomic_read(&connected_gsi->connected)) { + gsi_connected = true; + break; + } + } + + if (!gsi_connected) + connected_gsi = NULL; + + return connected_gsi; +} + +#define DEFAULT_RW_TIMER_INTERVAL 500 /* in ms */ +static ssize_t usb_gsi_rw_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + struct f_gsi *gsi; + u8 input; + int ret; + + gsi = get_connected_gsi(); + if (!gsi) { + log_event_dbg("%s: gsi not connected\n", __func__); + goto err; + } + + if (ubuf == NULL) { + log_event_dbg("%s: buffer is Null.\n", __func__); + goto err; + } + + ret = kstrtou8_from_user(ubuf, count, 0, &input); + if (ret) { + log_event_err("%s: Invalid value. err:%d\n", __func__, ret); + goto err; + } + + if (gsi->debugfs_rw_timer_enable == !!input) { + if (!!input) + log_event_dbg("%s: RW already enabled\n", __func__); + else + log_event_dbg("%s: RW already disabled\n", __func__); + goto err; + } + + gsi->debugfs_rw_timer_enable = !!input; + + if (gsi->debugfs_rw_timer_enable) { + mod_timer(&gsi->gsi_rw_timer, jiffies + + msecs_to_jiffies(gsi->gsi_rw_timer_interval)); + log_event_dbg("%s: timer initialized\n", __func__); + } else { + del_timer_sync(&gsi->gsi_rw_timer); + log_event_dbg("%s: timer deleted\n", __func__); + } + +err: + return count; +} + +static int usb_gsi_rw_show(struct seq_file *s, void *unused) +{ + + struct f_gsi *gsi; + + gsi = get_connected_gsi(); + if (!gsi) { + log_event_dbg("%s: gsi not connected\n", __func__); + return 0; + } + + seq_printf(s, "%d\n", gsi->debugfs_rw_timer_enable); + + return 0; +} + +static int usb_gsi_rw_open(struct inode *inode, struct file *f) +{ + return single_open(f, usb_gsi_rw_show, inode->i_private); +} + +static const struct file_operations fops_usb_gsi_rw = { + .open = usb_gsi_rw_open, + .read = seq_read, + .write = usb_gsi_rw_write, + .owner = THIS_MODULE, + .llseek = seq_lseek, + .release = seq_release, +}; + +static ssize_t usb_gsi_rw_timer_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) +{ + struct f_gsi *gsi; + u16 timer_val; + int ret; + + gsi = get_connected_gsi(); + if (!gsi) { + log_event_dbg("%s: gsi not connected\n", __func__); + goto err; + } + + if (ubuf == NULL) { + log_event_dbg("%s: buffer is NULL.\n", __func__); + goto err; + } + + ret = kstrtou16_from_user(ubuf, count, 0, &timer_val); + if (ret) { + log_event_err("%s: Invalid value. err:%d\n", __func__, ret); + goto err; + } + + if (timer_val <= 0 || timer_val > 10000) { + log_event_err("%s: value must be > 0 and < 10000.\n", __func__); + goto err; + } + + gsi->gsi_rw_timer_interval = timer_val; +err: + return count; +} + +static int usb_gsi_rw_timer_show(struct seq_file *s, void *unused) +{ + struct f_gsi *gsi; + + gsi = get_connected_gsi(); + if (!gsi) { + log_event_dbg("%s: gsi not connected\n", __func__); + return 0; + } + + seq_printf(s, "%ums\n", gsi->gsi_rw_timer_interval); + + return 0; +} + +static int usb_gsi_rw_timer_open(struct inode *inode, struct file *f) +{ + return single_open(f, usb_gsi_rw_timer_show, inode->i_private); +} + +static const struct file_operations fops_usb_gsi_rw_timer = { + .open = usb_gsi_rw_timer_open, + .read = seq_read, + .write = usb_gsi_rw_timer_write, + .owner = THIS_MODULE, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int usb_gsi_debugfs_init(void) +{ + debugfs.debugfs_root = debugfs_create_dir("usb_gsi", NULL); + if (!debugfs.debugfs_root) + return -ENOMEM; + + debugfs_create_file("remote_wakeup_enable", 0600, + debugfs.debugfs_root, + inst_status, &fops_usb_gsi_rw); + debugfs_create_file("remote_wakeup_interval", 0600, + debugfs.debugfs_root, + inst_status, + &fops_usb_gsi_rw_timer); + return 0; +} + +static void usb_gsi_debugfs_exit(void) +{ + debugfs_remove_recursive(debugfs.debugfs_root); +} + /* * Callback for when when network interface is up * and userspace is ready to answer DHCP requests, or remote wakeup @@ -373,9 +585,15 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) } /* Populate connection params */ - conn_params->max_pkt_size = - (cdev->gadget->speed >= USB_SPEED_SUPER) ? - IPA_USB_SUPER_SPEED_1024B : IPA_USB_HIGH_SPEED_512B; + if (cdev->gadget->speed >= USB_SPEED_SUPER) + conn_params->max_pkt_size = IPA_USB_SUPER_SPEED_1024B; + else if (cdev->gadget->speed == USB_SPEED_HIGH) + conn_params->max_pkt_size = IPA_USB_HIGH_SPEED_512B; + else + conn_params->max_pkt_size = IPA_USB_FULL_SPEED_64B; + + log_event_dbg("%s(): max_pkt_size:%d\n", __func__, + conn_params->max_pkt_size); conn_params->ipa_to_usb_xferrscidx = d_port->in_xfer_rsc_index; conn_params->usb_to_ipa_xferrscidx = @@ -392,7 +610,7 @@ static int ipa_connect_channels(struct gsi_data_port *d_port) conn_params->teth_prot_params.max_packet_number_to_dev = DEFAULT_MAX_PKT_PER_XFER; conn_params->max_supported_bandwidth_mbps = - (cdev->gadget->speed == USB_SPEED_SUPER) ? 3600 : 400; + (cdev->gadget->speed >= USB_SPEED_SUPER) ? 3600 : 400; memset(&ipa_in_channel_out_params, 0x0, sizeof(ipa_in_channel_out_params)); @@ -1399,7 +1617,7 @@ static const struct file_operations gsi_ctrl_dev_fops = { /* peak (theoretical) bulk transfer rate in bits-per-second */ static unsigned int gsi_xfer_bitrate(struct usb_gadget *g) { - if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER) + if (gadget_is_superspeed(g) && g->speed >= USB_SPEED_SUPER) return 13 * 1024 * 8 * 1000 * 8; else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) return 13 * 512 * 8 * 1000 * 8; @@ -2258,6 +2476,9 @@ static void gsi_disable(struct usb_function *f) atomic_set(&gsi->connected, 0); + del_timer(&gsi->gsi_rw_timer); + gsi->debugfs_rw_timer_enable = 0; + if (gsi->prot_id == IPA_USB_RNDIS) rndis_uninit(gsi->params); @@ -2306,6 +2527,16 @@ static void gsi_suspend(struct usb_function *f) post_event(&gsi->d_port, EVT_SUSPEND); queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w); log_event_dbg("gsi suspended"); + + /* + * If host suspended bus without receiving notification request then + * initiate remote-wakeup. As driver won't be able to do it later since + * notification request is already queued. + */ + if (gsi->c_port.notify_req_queued && usb_gsi_remote_wakeup_allowed(f)) { + mod_timer(&gsi->gsi_rw_timer, jiffies + msecs_to_jiffies(2000)); + log_event_dbg("%s: pending response, arm rw_timer\n", __func__); + } } static void gsi_resume(struct usb_function *f) @@ -2319,10 +2550,14 @@ static void gsi_resume(struct usb_function *f) * If the function is in USB3 Function Suspend state, resume is * canceled. In this case resume is done by a Function Resume request. */ - if ((cdev->gadget->speed == USB_SPEED_SUPER) && + if ((cdev->gadget->speed >= USB_SPEED_SUPER) && f->func_is_suspended) return; + /* Keep timer enabled if user enabled using debugfs */ + if (!gsi->debugfs_rw_timer_enable) + del_timer(&gsi->gsi_rw_timer); + if (gsi->c_port.notify && !gsi->c_port.notify->desc) config_ep_by_speed(cdev->gadget, f, gsi->c_port.notify); @@ -2347,6 +2582,11 @@ static void gsi_resume(struct usb_function *f) static int gsi_get_status(struct usb_function *f) { unsigned int remote_wakeup_en_status = f->func_wakeup_allowed ? 1 : 0; + struct f_gsi *gsi = func_to_gsi(f); + + /* Disable function remote wake-up for DPL interface */ + if (gsi->prot_id == IPA_USB_DIAG) + return 0; return (remote_wakeup_en_status << FUNC_WAKEUP_ENABLE_SHIFT) | (1 << FUNC_WAKEUP_CAPABLE_SHIFT); @@ -3054,6 +3294,8 @@ static struct f_gsi *gsi_function_init(enum ipa_usb_teth_prot prot_id) kfree(gsi); goto error; } + gsi->gsi_rw_timer_interval = DEFAULT_RW_TIMER_INTERVAL; + setup_timer(&gsi->gsi_rw_timer, gsi_rw_timer_func, (unsigned long) gsi); return gsi; error: @@ -3443,6 +3685,7 @@ static int fgsi_init(void) major = MAJOR(dev); + usb_gsi_debugfs_init(); return usb_function_register(&gsiusb_func); } module_init(fgsi_init); @@ -3459,5 +3702,6 @@ static void __exit fgsi_exit(void) } class_destroy(gsi_class); + usb_gsi_debugfs_exit(); } module_exit(fgsi_exit); diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h index 06b1bb4845314783d71947e6d08c8997d8dbd0fa..db8c4925657a9b0266469f7edc64a332d8953a2a 100644 --- a/drivers/usb/gadget/function/f_gsi.h +++ b/drivers/usb/gadget/function/f_gsi.h @@ -26,6 +26,7 @@ #include #include #include +#include #define GSI_RMNET_CTRL_NAME "rmnet_ctrl" #define GSI_MBIM_CTRL_NAME "android_mbim" @@ -280,6 +281,12 @@ struct f_gsi { struct gsi_ctrl_port c_port; void *ipc_log_ctxt; bool rmnet_dtr_status; + + /* To test remote wakeup using debugfs */ + struct timer_list gsi_rw_timer; + u8 debugfs_rw_timer_enable; + u16 gsi_rw_timer_interval; + }; static inline struct f_gsi *func_to_gsi(struct usb_function *f) diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 5153e29870c3917fe4cdefc1e4c920536cdd4bf4..c5b93889e13a843f3cac1fd304225bea32b3f4dc 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -2222,6 +2222,8 @@ static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg) fsg->bulk_out_enabled = 0; } + /* allow usb LPM after eps are disabled */ + usb_gadget_autopm_put_async(common->gadget); common->fsg = NULL; wake_up(&common->fsg_wait); } @@ -2286,6 +2288,10 @@ static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) { struct fsg_dev *fsg = fsg_from_func(f); fsg->common->new_fsg = fsg; + + /* prevents usb LPM until thread runs to completion */ + usb_gadget_autopm_get_async(fsg->common->gadget); + raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); return USB_GADGET_DELAYED_STATUS; } diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index d0faf68a648ce97d426dd351a64c93fbc7131ecb..f1429ba14aef074e30b98b345b83d275e097d103 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -1627,7 +1627,8 @@ int ncm_ctrlrequest(struct usb_composite_dev *cdev, { int value = -EOPNOTSUPP; - if (ctrl->bRequestType == 0x40 && ctrl->bRequest == 0xF0) { + if (ctrl->bRequestType == 0x40 && ctrl->bRequest == 0xF0 + && _ncm_setup_desc) { _ncm_setup_desc->minor = (uint8_t)(ctrl->wValue >> 8); _ncm_setup_desc->major = (uint8_t)(ctrl->wValue & 0xFF); schedule_work(&_ncm_setup_desc->work); @@ -1700,6 +1701,8 @@ static void ncm_unbind(struct usb_configuration *c, struct usb_function *f) DBG(c->cdev, "ncm unbind\n"); + opts->bound = false; + hrtimer_cancel(&ncm->task_timer); tasklet_kill(&ncm->tx_tasklet); @@ -1710,7 +1713,6 @@ static void ncm_unbind(struct usb_configuration *c, struct usb_function *f) usb_ep_free_request(ncm->notify, ncm->notify_req); gether_cleanup(netdev_priv(opts->net)); - opts->bound = false; } static struct usb_function *ncm_alloc(struct usb_function_instance *fi) diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c index 4313fa8790b261d3978f605629881989704496e1..b230d94d8a23094e926b278864cfe8b624562c01 100644 --- a/drivers/usb/gadget/function/f_qdss.c +++ b/drivers/usb/gadget/function/f_qdss.c @@ -677,7 +677,6 @@ static int qdss_set_alt(struct usb_function *f, unsigned int intf, if (gadget->speed < USB_SPEED_HIGH) { pr_err("%s: qdss doesn't support USB full or low speed\n", __func__); - ret = -EINVAL; goto fail1; } diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 619d0f0bca2be39bb5263a2e726e2d59d76b882e..574a63a655d05b1f714e3251baa30f182cd1cf2d 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -491,14 +491,14 @@ static struct usb_descriptor_header *ss_audio_desc[] = { }; struct cntrl_cur_lay3 { - __u32 dCUR; + __le32 dCUR; }; struct cntrl_range_lay3 { - __u16 wNumSubRanges; - __u32 dMIN; - __u32 dMAX; - __u32 dRES; + __le16 wNumSubRanges; + __le32 dMIN; + __le32 dMAX; + __le32 dRES; } __packed; static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts, @@ -613,13 +613,13 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc); if (!agdev->out_ep) { dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); - return ret; + return -ENODEV; } agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc); if (!agdev->in_ep) { dev_err(dev, "%s:%d Error!\n", __func__, __LINE__); - return ret; + return -ENODEV; } agdev->in_ep_maxpsize = max_t(u16, @@ -757,9 +757,9 @@ in_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr) memset(&c, 0, sizeof(struct cntrl_cur_lay3)); if (entity_id == USB_IN_CLK_ID) - c.dCUR = p_srate; + c.dCUR = cpu_to_le32(p_srate); else if (entity_id == USB_OUT_CLK_ID) - c.dCUR = c_srate; + c.dCUR = cpu_to_le32(c_srate); value = min_t(unsigned, w_length, sizeof c); memcpy(req->buf, &c, value); @@ -796,15 +796,15 @@ in_rq_range(struct usb_function *fn, const struct usb_ctrlrequest *cr) if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) { if (entity_id == USB_IN_CLK_ID) - r.dMIN = p_srate; + r.dMIN = cpu_to_le32(p_srate); else if (entity_id == USB_OUT_CLK_ID) - r.dMIN = c_srate; + r.dMIN = cpu_to_le32(c_srate); else return -EOPNOTSUPP; r.dMAX = r.dMIN; r.dRES = 0; - r.wNumSubRanges = 1; + r.wNumSubRanges = cpu_to_le16(1); value = min_t(unsigned, w_length, sizeof r); memcpy(req->buf, &r, value); diff --git a/drivers/usb/gadget/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c index 147a958be7caa62c6bff5909adb90fd35669bec9..435f0614d57206e9cccf0e82b67e28918f2c5fc4 100644 --- a/drivers/usb/gadget/function/u_audio.c +++ b/drivers/usb/gadget/function/u_audio.c @@ -41,9 +41,6 @@ struct uac_req { struct uac_rtd_params { struct snd_uac_chip *uac; /* parent chip */ bool ep_enabled; /* if the ep is enabled */ - /* Size of the ring buffer */ - size_t dma_bytes; - unsigned char *dma_area; struct snd_pcm_substream *ss; @@ -52,8 +49,6 @@ struct uac_rtd_params { void *rbuf; - size_t period_size; - unsigned max_psize; /* MaxPacketSize of endpoint */ struct uac_req *ureq; @@ -93,12 +88,12 @@ static const struct snd_pcm_hardware uac_pcm_hardware = { static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req) { unsigned pending; - unsigned long flags; + unsigned long flags, flags2; unsigned int hw_ptr; - bool update_alsa = false; int status = req->status; struct uac_req *ur = req->context; struct snd_pcm_substream *substream; + struct snd_pcm_runtime *runtime; struct uac_rtd_params *prm = ur->pp; struct snd_uac_chip *uac = prm->uac; @@ -120,6 +115,14 @@ static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req) if (!substream) goto exit; + snd_pcm_stream_lock_irqsave(substream, flags2); + + runtime = substream->runtime; + if (!runtime || !snd_pcm_running(substream)) { + snd_pcm_stream_unlock_irqrestore(substream, flags2); + goto exit; + } + spin_lock_irqsave(&prm->lock, flags); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { @@ -146,43 +149,46 @@ static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req) req->actual = req->length; } - pending = prm->hw_ptr % prm->period_size; - pending += req->actual; - if (pending >= prm->period_size) - update_alsa = true; - hw_ptr = prm->hw_ptr; - prm->hw_ptr = (prm->hw_ptr + req->actual) % prm->dma_bytes; spin_unlock_irqrestore(&prm->lock, flags); /* Pack USB load in ALSA ring buffer */ - pending = prm->dma_bytes - hw_ptr; + pending = runtime->dma_bytes - hw_ptr; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (unlikely(pending < req->actual)) { - memcpy(req->buf, prm->dma_area + hw_ptr, pending); - memcpy(req->buf + pending, prm->dma_area, + memcpy(req->buf, runtime->dma_area + hw_ptr, pending); + memcpy(req->buf + pending, runtime->dma_area, req->actual - pending); } else { - memcpy(req->buf, prm->dma_area + hw_ptr, req->actual); + memcpy(req->buf, runtime->dma_area + hw_ptr, + req->actual); } } else { if (unlikely(pending < req->actual)) { - memcpy(prm->dma_area + hw_ptr, req->buf, pending); - memcpy(prm->dma_area, req->buf + pending, + memcpy(runtime->dma_area + hw_ptr, req->buf, pending); + memcpy(runtime->dma_area, req->buf + pending, req->actual - pending); } else { - memcpy(prm->dma_area + hw_ptr, req->buf, req->actual); + memcpy(runtime->dma_area + hw_ptr, req->buf, + req->actual); } } + spin_lock_irqsave(&prm->lock, flags); + /* update hw_ptr after data is copied to memory */ + prm->hw_ptr = (hw_ptr + req->actual) % runtime->dma_bytes; + hw_ptr = prm->hw_ptr; + spin_unlock_irqrestore(&prm->lock, flags); + snd_pcm_stream_unlock_irqrestore(substream, flags2); + + if ((hw_ptr % snd_pcm_lib_period_bytes(substream)) < req->actual) + snd_pcm_period_elapsed(substream); + exit: if (usb_ep_queue(ep, req, GFP_ATOMIC)) dev_err(uac->card->dev, "%d Error!\n", __LINE__); - - if (update_alsa) - snd_pcm_period_elapsed(substream); } static int uac_pcm_trigger(struct snd_pcm_substream *substream, int cmd) @@ -245,40 +251,12 @@ static snd_pcm_uframes_t uac_pcm_pointer(struct snd_pcm_substream *substream) static int uac_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { - struct snd_uac_chip *uac = snd_pcm_substream_chip(substream); - struct uac_rtd_params *prm; - int err; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - prm = &uac->p_prm; - else - prm = &uac->c_prm; - - err = snd_pcm_lib_malloc_pages(substream, + return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); - if (err >= 0) { - prm->dma_bytes = substream->runtime->dma_bytes; - prm->dma_area = substream->runtime->dma_area; - prm->period_size = params_period_bytes(hw_params); - } - - return err; } static int uac_pcm_hw_free(struct snd_pcm_substream *substream) { - struct snd_uac_chip *uac = snd_pcm_substream_chip(substream); - struct uac_rtd_params *prm; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - prm = &uac->p_prm; - else - prm = &uac->c_prm; - - prm->dma_area = NULL; - prm->dma_bytes = 0; - prm->period_size = 0; - return snd_pcm_lib_free_pages(substream); } @@ -609,15 +587,15 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name, if (err < 0) goto snd_fail; - strcpy(pcm->name, pcm_name); + strlcpy(pcm->name, pcm_name, sizeof(pcm->name)); pcm->private_data = uac; uac->pcm = pcm; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &uac_pcm_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &uac_pcm_ops); - strcpy(card->driver, card_name); - strcpy(card->shortname, card_name); + strlcpy(card->driver, card_name, sizeof(card->driver)); + strlcpy(card->shortname, card_name, sizeof(card->shortname)); sprintf(card->longname, "%s %i", card_name, card->dev->id); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, diff --git a/drivers/usb/gadget/function/u_ether_configfs.h b/drivers/usb/gadget/function/u_ether_configfs.h index cea4a0abeaaea31fadfaf3b35584da963b038b8e..bb6524a1be0ddfe73c07a153d3b8b5b0c53e38b1 100644 --- a/drivers/usb/gadget/function/u_ether_configfs.h +++ b/drivers/usb/gadget/function/u_ether_configfs.h @@ -35,6 +35,11 @@ struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ int result; \ \ + if (opts->bound == false) { \ + pr_err("Gadget function do not bind yet.\n"); \ + return -ENODEV; \ + } \ + \ mutex_lock(&opts->lock); \ result = gether_get_dev_addr(opts->net, page, PAGE_SIZE); \ mutex_unlock(&opts->lock); \ @@ -48,6 +53,11 @@ struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ int ret; \ \ + if (opts->bound == false) { \ + pr_err("Gadget function do not bind yet.\n"); \ + return -ENODEV; \ + } \ + \ mutex_lock(&opts->lock); \ if (opts->refcnt) { \ mutex_unlock(&opts->lock); \ @@ -70,6 +80,11 @@ struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ int result; \ \ + if (opts->bound == false) { \ + pr_err("Gadget function do not bind yet.\n"); \ + return -ENODEV; \ + } \ + \ mutex_lock(&opts->lock); \ result = gether_get_host_addr(opts->net, page, PAGE_SIZE); \ mutex_unlock(&opts->lock); \ @@ -83,6 +98,11 @@ struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ int ret; \ \ + if (opts->bound == false) { \ + pr_err("Gadget function do not bind yet.\n"); \ + return -ENODEV; \ + } \ + \ mutex_lock(&opts->lock); \ if (opts->refcnt) { \ mutex_unlock(&opts->lock); \ @@ -105,6 +125,11 @@ struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ unsigned qmult; \ \ + if (opts->bound == false) { \ + pr_err("Gadget function do not bind yet.\n"); \ + return -ENODEV; \ + } \ + \ mutex_lock(&opts->lock); \ qmult = gether_get_qmult(opts->net); \ mutex_unlock(&opts->lock); \ @@ -118,6 +143,11 @@ u8 val; \ int ret; \ \ + if (opts->bound == false) { \ + pr_err("Gadget function do not bind yet.\n"); \ + return -ENODEV; \ + } \ + \ mutex_lock(&opts->lock); \ if (opts->refcnt) { \ ret = -EBUSY; \ @@ -144,6 +174,11 @@ out: \ struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \ int ret; \ \ + if (opts->bound == false) { \ + pr_err("Gadget function do not bind yet.\n"); \ + return -ENODEV; \ + } \ + \ mutex_lock(&opts->lock); \ ret = gether_get_ifname(opts->net, page, PAGE_SIZE); \ mutex_unlock(&opts->lock); \ diff --git a/drivers/usb/gadget/udc/fotg210-udc.c b/drivers/usb/gadget/udc/fotg210-udc.c index 78d0204e3e20a5ef91e3c2e8988ae2f0c69f661c..d17d7052605ba40e0dca04336be44a9ee28fb7d0 100644 --- a/drivers/usb/gadget/udc/fotg210-udc.c +++ b/drivers/usb/gadget/udc/fotg210-udc.c @@ -1066,12 +1066,15 @@ static const struct usb_gadget_ops fotg210_gadget_ops = { static int fotg210_udc_remove(struct platform_device *pdev) { struct fotg210_udc *fotg210 = platform_get_drvdata(pdev); + int i; usb_del_gadget_udc(&fotg210->gadget); iounmap(fotg210->reg); free_irq(platform_get_irq(pdev, 0), fotg210); fotg210_ep_free_request(&fotg210->ep[0]->ep, fotg210->ep0_req); + for (i = 0; i < FOTG210_MAX_NUM_EP; i++) + kfree(fotg210->ep[i]); kfree(fotg210); return 0; @@ -1102,7 +1105,7 @@ static int fotg210_udc_probe(struct platform_device *pdev) /* initialize udc */ fotg210 = kzalloc(sizeof(struct fotg210_udc), GFP_KERNEL); if (fotg210 == NULL) - goto err_alloc; + goto err; for (i = 0; i < FOTG210_MAX_NUM_EP; i++) { _ep[i] = kzalloc(sizeof(struct fotg210_ep), GFP_KERNEL); @@ -1114,7 +1117,7 @@ static int fotg210_udc_probe(struct platform_device *pdev) fotg210->reg = ioremap(res->start, resource_size(res)); if (fotg210->reg == NULL) { pr_err("ioremap error.\n"); - goto err_map; + goto err_alloc; } spin_lock_init(&fotg210->lock); @@ -1162,7 +1165,7 @@ static int fotg210_udc_probe(struct platform_device *pdev) fotg210->ep0_req = fotg210_ep_alloc_request(&fotg210->ep[0]->ep, GFP_KERNEL); if (fotg210->ep0_req == NULL) - goto err_req; + goto err_map; fotg210_init(fotg210); @@ -1190,12 +1193,14 @@ static int fotg210_udc_probe(struct platform_device *pdev) fotg210_ep_free_request(&fotg210->ep[0]->ep, fotg210->ep0_req); err_map: - if (fotg210->reg) - iounmap(fotg210->reg); + iounmap(fotg210->reg); err_alloc: + for (i = 0; i < FOTG210_MAX_NUM_EP; i++) + kfree(fotg210->ep[i]); kfree(fotg210); +err: return ret; } diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index f608c1f85e611f2a36fd6389006e3f00837a7035..9cbb061582a774676eb6cf4d42b8d84eb19b10f3 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c @@ -1549,11 +1549,14 @@ static int net2280_pullup(struct usb_gadget *_gadget, int is_on) writel(tmp | BIT(USB_DETECT_ENABLE), &dev->usb->usbctl); } else { writel(tmp & ~BIT(USB_DETECT_ENABLE), &dev->usb->usbctl); - stop_activity(dev, dev->driver); + stop_activity(dev, NULL); } spin_unlock_irqrestore(&dev->lock, flags); + if (!is_on && dev->driver) + dev->driver->disconnect(&dev->gadget); + return 0; } @@ -2470,8 +2473,11 @@ static void stop_activity(struct net2280 *dev, struct usb_gadget_driver *driver) nuke(&dev->ep[i]); /* report disconnect; the driver is already quiesced */ - if (driver) + if (driver) { + spin_unlock(&dev->lock); driver->disconnect(&dev->gadget); + spin_lock(&dev->lock); + } usb_reinit(dev); } @@ -3345,6 +3351,8 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat) BIT(PCI_RETRY_ABORT_INTERRUPT)) static void handle_stat1_irqs(struct net2280 *dev, u32 stat) +__releases(dev->lock) +__acquires(dev->lock) { struct net2280_ep *ep; u32 tmp, num, mask, scratch; @@ -3385,12 +3393,14 @@ static void handle_stat1_irqs(struct net2280 *dev, u32 stat) if (disconnect || reset) { stop_activity(dev, dev->driver); ep0_start(dev); + spin_unlock(&dev->lock); if (reset) usb_gadget_udc_reset (&dev->gadget, dev->driver); else (dev->driver->disconnect) (&dev->gadget); + spin_lock(&dev->lock); return; } } @@ -3409,6 +3419,7 @@ static void handle_stat1_irqs(struct net2280 *dev, u32 stat) tmp = BIT(SUSPEND_REQUEST_CHANGE_INTERRUPT); if (stat & tmp) { writel(tmp, &dev->regs->irqstat1); + spin_unlock(&dev->lock); if (stat & BIT(SUSPEND_REQUEST_INTERRUPT)) { if (dev->driver->suspend) dev->driver->suspend(&dev->gadget); @@ -3419,6 +3430,7 @@ static void handle_stat1_irqs(struct net2280 *dev, u32 stat) dev->driver->resume(&dev->gadget); /* at high speed, note erratum 0133 */ } + spin_lock(&dev->lock); stat &= ~tmp; } diff --git a/drivers/usb/gadget/udc/r8a66597-udc.c b/drivers/usb/gadget/udc/r8a66597-udc.c index 118ad70f1af0f109714a83cfd4b48327382c3268..84b227ede08232eca9fd1b3602150c06a5fdff4c 100644 --- a/drivers/usb/gadget/udc/r8a66597-udc.c +++ b/drivers/usb/gadget/udc/r8a66597-udc.c @@ -835,11 +835,11 @@ static void init_controller(struct r8a66597 *r8a66597) r8a66597_bset(r8a66597, XCKE, SYSCFG0); - msleep(3); + mdelay(3); r8a66597_bset(r8a66597, PLLC, SYSCFG0); - msleep(1); + mdelay(1); r8a66597_bset(r8a66597, SCKE, SYSCFG0); @@ -1193,7 +1193,7 @@ __acquires(r8a66597->lock) r8a66597->ep0_req->length = 2; /* AV: what happens if we get called again before that gets through? */ spin_unlock(&r8a66597->lock); - r8a66597_queue(r8a66597->gadget.ep0, r8a66597->ep0_req, GFP_KERNEL); + r8a66597_queue(r8a66597->gadget.ep0, r8a66597->ep0_req, GFP_ATOMIC); spin_lock(&r8a66597->lock); } diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index c12a1a6554bad90bd36d805e3805453f433c5121..36a706f475d251d89bbbcac46258aec724393e10 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -788,12 +788,15 @@ static void usb3_irq_epc_int_1_speed(struct renesas_usb3 *usb3) switch (speed) { case USB_STA_SPEED_SS: usb3->gadget.speed = USB_SPEED_SUPER; + usb3->gadget.ep0->maxpacket = USB3_EP0_SS_MAX_PACKET_SIZE; break; case USB_STA_SPEED_HS: usb3->gadget.speed = USB_SPEED_HIGH; + usb3->gadget.ep0->maxpacket = USB3_EP0_HSFS_MAX_PACKET_SIZE; break; case USB_STA_SPEED_FS: usb3->gadget.speed = USB_SPEED_FULL; + usb3->gadget.ep0->maxpacket = USB3_EP0_HSFS_MAX_PACKET_SIZE; break; default: usb3->gadget.speed = USB_SPEED_UNKNOWN; @@ -2458,7 +2461,7 @@ static int renesas_usb3_init_ep(struct renesas_usb3 *usb3, struct device *dev, /* for control pipe */ usb3->gadget.ep0 = &usb3_ep->ep; usb_ep_set_maxpacket_limit(&usb3_ep->ep, - USB3_EP0_HSFS_MAX_PACKET_SIZE); + USB3_EP0_SS_MAX_PACKET_SIZE); usb3_ep->ep.caps.type_control = true; usb3_ep->ep.caps.dir_in = true; usb3_ep->ep.caps.dir_out = true; diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index c38855aed62c7df6ef3c7e134eae2c9b0e787da2..65c0086e25ae6d8ac1a302308e954ef15d88c41d 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -2559,7 +2559,7 @@ static int u132_get_frame(struct usb_hcd *hcd) } else { int frame = 0; dev_err(&u132->platform_dev->dev, "TODO: u132_get_frame\n"); - msleep(100); + mdelay(100); return frame; } } diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c index 8fb60657ed4fd7a73525fd949518fc6bf4119ac4..510d28a9d1901937921d9f1778e9ca74ebf99c85 100644 --- a/drivers/usb/host/xhci-mtk.c +++ b/drivers/usb/host/xhci-mtk.c @@ -780,10 +780,10 @@ static int __maybe_unused xhci_mtk_resume(struct device *dev) xhci_mtk_host_enable(mtk); xhci_dbg(xhci, "%s: restart port polling\n", __func__); - set_bit(HCD_FLAG_POLL_RH, &hcd->flags); - usb_hcd_poll_rh_status(hcd); set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags); usb_hcd_poll_rh_status(xhci->shared_hcd); + set_bit(HCD_FLAG_POLL_RH, &hcd->flags); + usb_hcd_poll_rh_status(hcd); return 0; } diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 838d37e79fa22f1e7f22d26847282a04ce907244..9218f506f8e332b8de014ac367bdb9f2bb1aaaed 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -196,6 +196,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) } if (pdev->vendor == PCI_VENDOR_ID_INTEL && (pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_DNV_XHCI)) xhci->quirks |= XHCI_MISSING_CAS; diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index 74436f8ca5382f736dbf352c21b7c2f83a8438ba..32ddafe7af87d08276a03118e46b6e7b8f5494e6 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c @@ -482,7 +482,7 @@ static void tegra_xusb_mbox_handle(struct tegra_xusb *tegra, unsigned long mask; unsigned int port; bool idle, enable; - int err; + int err = 0; memset(&rsp, 0, sizeof(rsp)); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 8cc779d9c99890ba23421002f7719cdbcf129b86..ad87c69869c9dc55059a1f3ad1796212f70c2512 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -47,6 +47,21 @@ static unsigned int quirks; module_param(quirks, uint, S_IRUGO); MODULE_PARM_DESC(quirks, "Bit flags for quirks to be enabled as default"); +static bool td_on_ring(struct xhci_td *td, struct xhci_ring *ring) +{ + struct xhci_segment *seg = ring->first_seg; + + if (!td || !td->start_seg) + return false; + do { + if (seg == td->start_seg) + return true; + seg = seg->next; + } while (seg && seg != ring->first_seg); + + return false; +} + /* TODO: copied from ehci-hcd.c - can this be refactored? */ /* * xhci_handshake - spin reading hc until handshake completes or fails @@ -1030,8 +1045,13 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) command = readl(&xhci->op_regs->command); command |= CMD_CRS; writel(command, &xhci->op_regs->command); + /* + * Some controllers take up to 55+ ms to complete the controller + * restore so setting the timeout to 100ms. Xhci specification + * doesn't mention any timeout value. + */ if (xhci_handshake(&xhci->op_regs->status, - STS_RESTORE, 0, 10 * 1000)) { + STS_RESTORE, 0, 100 * 1000)) { xhci_warn(xhci, "WARN: xHC restore state timeout\n"); spin_unlock_irq(&xhci->lock); return -ETIMEDOUT; @@ -1512,6 +1532,21 @@ static int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) goto done; } + /* + * check ring is not re-allocated since URB was enqueued. If it is, then + * make sure none of the ring related pointers in this URB private data + * are touched, such as td_list, otherwise we overwrite freed data + */ + if (!td_on_ring(&urb_priv->td[0], ep_ring)) { + xhci_err(xhci, "Canceled URB td not found on endpoint ring"); + for (i = urb_priv->num_tds_done; i < urb_priv->num_tds; i++) { + td = &urb_priv->td[i]; + if (!list_empty(&td->cancelled_td_list)) + list_del_init(&td->cancelled_td_list); + } + goto err_giveback; + } + if (xhci->xhc_state & XHCI_STATE_HALTED) { xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, "HC halted, freeing TD manually."); diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 740db57464fc21814afc0102bd13d7aeda0b55c5..3118935961cc4f06e837e4ff24ce94ef83cc8218 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -281,3 +281,9 @@ config USB_REDRIVER_NB7VPQ904M depends on USB_PHY help Say Y here if you want to support USB super speed re-driver NB7VPQ904M. + +config USB_TYPEC_MUX_NXP5150A + tristate "Enable driver for NXP CC Logic chipset NXP5150A" + help + Say Y here if you want to use NXP CC Logic Type-C Chipset NXP5150A + for CC detection and Mux control. diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 4f7d20242470f7e9b7057f2d97512f7bb8225291..37baeaa384fc99631c14b0d84abe131cc56efb04 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_USB_HUB_USB251XB) += usb251xb.o obj-$(CONFIG_USB_HSIC_USB3503) += usb3503.o obj-$(CONFIG_USB_HSIC_USB4604) += usb4604.o obj-$(CONFIG_USB_CHAOSKEY) += chaoskey.o +obj-$(CONFIG_USB_TYPEC_MUX_NXP5150A) += nxp_typec.o obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/ obj-$(CONFIG_USB_LINK_LAYER_TEST) += lvstest.o diff --git a/drivers/usb/misc/nxp_typec.c b/drivers/usb/misc/nxp_typec.c new file mode 100644 index 0000000000000000000000000000000000000000..df6c6767a95e42875d292f858eee8eddd9fd4789 --- /dev/null +++ b/drivers/usb/misc/nxp_typec.c @@ -0,0 +1,262 @@ +/* Copyright (c) 2018, Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include + +#define CONTROL_REG 0x02 +#define STATUS_REG 0x04 +#define INTR_MASK_REG 0x18 +#define INTR_STATUS_REG 0x19 + +#define DISABLE_CABLE_INTR 0x05 +#define ENABLE_ROLE_CHANGE_INTR 0x08 + +#define ROLE_CHANGE_INTR_STATUS BIT(3) +#define GET_PORT_ROLE(n) (((n) >> 2) & 0x03) + +struct nxpusb5150a { + struct device *dev; + struct regmap *regmap; + struct extcon_dev *extcon; + + struct gpio_desc *vbus_out_gpio; +}; + +enum port_role { + PORT_ROLE_DISCONNECTED, + PORT_ROLE_UFP, + PORT_ROLE_DFP, +}; + +static const unsigned int nxpusb5150a_extcon_cable[] = { + EXTCON_USB_HOST, + EXTCON_NONE, +}; + +static const struct regmap_config nxpusb5150a_regmap = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int nxpusb5150a_read_reg(struct nxpusb5150a *nxp, u8 reg, u8 *val) +{ + int ret; + unsigned int reg_val; + + ret = regmap_read(nxp->regmap, (unsigned int)reg, ®_val); + if (ret < 0) { + dev_err(nxp->dev, "Failed to read reg:0x%02x\n", reg); + return ret; + } + + *val = (u8)reg_val; + dev_dbg(nxp->dev, "read reg:0x%02x val:0x%02x\n", reg, *val); + + return 0; +} + +static int nxpusb5150a_write_reg(struct nxpusb5150a *nxp, u8 reg, u8 mask, + u8 val) +{ + int ret; + u8 reg_val; + + ret = nxpusb5150a_read_reg(nxp, reg, ®_val); + if (ret) + return ret; + + val |= (reg_val & mask); + ret = regmap_write(nxp->regmap, (unsigned int)reg, (unsigned int)val); + if (ret < 0) { + dev_err(nxp->dev, "failed to write 0x%02x to reg: 0x%02x\n", + val, reg); + return ret; + } + + dev_dbg(nxp->dev, "write reg:0x%02x val:0x%02x\n", reg, val); + + return 0; +} +static irqreturn_t nxusb5150a_cable_thread_handler(int irq, void *dev_id) +{ + struct nxpusb5150a *nxp = dev_id; + union extcon_property_value val; + u8 status; + enum port_role role; + int ret; + + ret = nxpusb5150a_read_reg(nxp, INTR_STATUS_REG, &status); + if (ret) + goto error; + + if (!(status & ROLE_CHANGE_INTR_STATUS)) { + dev_dbg(nxp->dev, "No change in role of port\n"); + return IRQ_HANDLED; + } + + ret = nxpusb5150a_read_reg(nxp, STATUS_REG, &status); + if (ret) + goto error; + + role = GET_PORT_ROLE(status); + switch (role) { + case PORT_ROLE_DFP: + val.intval = 1; + if (nxp->vbus_out_gpio) + gpiod_set_value_cansleep(nxp->vbus_out_gpio, 1); + extcon_set_state_sync(nxp->extcon, EXTCON_USB_HOST, 1); + break; + + case PORT_ROLE_UFP: + dev_err(nxp->dev, "Port does not support device mode(UFP)\n"); + case PORT_ROLE_DISCONNECTED: + default: + if (nxp->vbus_out_gpio) + gpiod_set_value_cansleep(nxp->vbus_out_gpio, 0); + extcon_set_state_sync(nxp->extcon, EXTCON_USB_HOST, 0); + break; + } + + return IRQ_HANDLED; + + /* + * Register read failures are treated as errors. + * So notify the state as disconnected whenever the failures are seen. + */ +error: + if (nxp->vbus_out_gpio) + gpiod_set_value_cansleep(nxp->vbus_out_gpio, 0); + extcon_set_state_sync(nxp->extcon, EXTCON_USB_HOST, 0); + + return IRQ_HANDLED; +} + +/* + * Configure the NXP 5150a chipset to enable the role change + * interrupt and disable the remaining interrupts. + */ +static int nxpusb5150a_configure_interrupts(struct nxpusb5150a *nxp) +{ + int ret; + + /* + * Cable detach and attach interrupts are enabled after + * reset. So disable the same. + * Also set the mode to DRP so that the chipset can + * detect DFP connections. + */ + ret = nxpusb5150a_write_reg(nxp, CONTROL_REG, ~DISABLE_CABLE_INTR, + DISABLE_CABLE_INTR); + if (ret) + return ret; + + /* Enable the interrupt to detect role change.*/ + ret = nxpusb5150a_write_reg(nxp, INTR_MASK_REG, + ~ENABLE_ROLE_CHANGE_INTR, 0); + if (ret) + return ret; + + return 0; +} + +static int nxpusb5150a_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct nxpusb5150a *nxp; + int ret; + + nxp = devm_kzalloc(dev, sizeof(nxp), GFP_KERNEL); + if (!nxp) + return -ENOMEM; + + nxp->dev = dev; + + nxp->regmap = devm_regmap_init_i2c(client, &nxpusb5150a_regmap); + if (IS_ERR(nxp->regmap)) { + dev_err(nxp->dev, "Failed to allocate register map: %d\n", + PTR_ERR(nxp->regmap)); + return PTR_ERR(nxp->regmap); + } + + i2c_set_clientdata(client, nxp); + + nxp->extcon = devm_extcon_dev_allocate(dev, nxpusb5150a_extcon_cable); + if (IS_ERR(nxp->extcon)) { + dev_err(nxp->dev, "Failed to allocate extcon device: %d\n", + PTR_ERR(nxp->extcon)); + return PTR_ERR(nxp->extcon); + } + + ret = devm_extcon_dev_register(dev, nxp->extcon); + if (ret) { + dev_err(nxp->dev, "Failed to register extcon device: %d\n", + ret); + return ret; + } + + nxp->vbus_out_gpio = devm_gpiod_get_optional(nxp->dev, "vbus-out", + GPIOD_OUT_HIGH); + if (!nxp->vbus_out_gpio) + dev_err(dev, "No external VBUS GPIO supplied\n"); + + if (!client->irq) { + dev_err(dev, "no client irq\n"); + return -EINVAL; + } + + ret = devm_request_threaded_irq(dev, client->irq, NULL, + nxusb5150a_cable_thread_handler, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + client->name, nxp); + if (ret < 0) { + dev_err(nxp->dev, "Failed to request interrupt handler\n"); + return ret; + } + + ret = nxpusb5150a_configure_interrupts(nxp); + if (ret) { + dev_err(dev, "failed to configure interrupts\n"); + return ret; + } + + nxusb5150a_cable_thread_handler(client->irq, nxp); + + return 0; +} + +static const struct of_device_id nxpusb5150a_match_table[] = { + { .compatible = "nxp,5150a",}, + { }, +}; + +static const struct i2c_device_id nxpusb5150a_table[] = { + { "nxpusb5150a" }, + {} +}; +MODULE_DEVICE_TABLE(i2c, nxpusb5150a_table); + +static struct i2c_driver nxpusb5150a_driver = { + .driver = { + .name = "nxpusb5150a", + .owner = THIS_MODULE, + .of_match_table = nxpusb5150a_match_table, + }, + .probe_new = nxpusb5150a_probe, + .id_table = nxpusb5150a_table, +}; +module_i2c_driver(nxpusb5150a_driver); diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c index 8a13b2fcf3e135d0403f1e6d40641906e45277f9..03152f98108c784ef6cb2d5951bb39b8f2921c88 100644 --- a/drivers/usb/misc/uss720.c +++ b/drivers/usb/misc/uss720.c @@ -382,7 +382,7 @@ static unsigned char parport_uss720_frob_control(struct parport *pp, unsigned ch mask &= 0x0f; val &= 0x0f; d = (priv->reg[1] & (~mask)) ^ val; - if (set_1284_register(pp, 2, d, GFP_KERNEL)) + if (set_1284_register(pp, 2, d, GFP_ATOMIC)) return 0; priv->reg[1] = d; return d & 0xf; @@ -392,7 +392,7 @@ static unsigned char parport_uss720_read_status(struct parport *pp) { unsigned char ret; - if (get_1284_register(pp, 1, &ret, GFP_KERNEL)) + if (get_1284_register(pp, 1, &ret, GFP_ATOMIC)) return 0; return ret & 0xf8; } diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c index 47763311a42e15a20eae8eee6b2b0427541ba773..4f48f5730e12664ecffd6b2c2cbecf8ad98aca43 100644 --- a/drivers/usb/misc/yurex.c +++ b/drivers/usb/misc/yurex.c @@ -417,6 +417,9 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count, spin_unlock_irqrestore(&dev->lock, flags); mutex_unlock(&dev->io_mutex); + if (WARN_ON_ONCE(len >= sizeof(in_buffer))) + return -EIO; + return simple_read_from_buffer(buffer, count, ppos, in_buffer, len); } @@ -425,13 +428,13 @@ static ssize_t yurex_write(struct file *file, const char __user *user_buffer, { struct usb_yurex *dev; int i, set = 0, retval = 0; - char buffer[16]; + char buffer[16 + 1]; char *data = buffer; unsigned long long c, c2 = 0; signed long timeout = 0; DEFINE_WAIT(wait); - count = min(sizeof(buffer), count); + count = min(sizeof(buffer) - 1, count); dev = file->private_data; /* verify that we actually have some data to write */ @@ -450,6 +453,7 @@ static ssize_t yurex_write(struct file *file, const char __user *user_buffer, retval = -EFAULT; goto error; } + buffer[count] = 0; memset(dev->cntl_buffer, CMD_PADDING, YUREX_BUF_SIZE); switch (buffer[0]) { diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index f6b526606ad1092494f3d8eaac6946bd77069ad2..dbb482b7e0ba61181b6eb2be614e312b55240893 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -684,16 +684,6 @@ dsps_dma_controller_create(struct musb *musb, void __iomem *base) return controller; } -static void dsps_dma_controller_destroy(struct dma_controller *c) -{ - struct musb *musb = c->musb; - struct dsps_glue *glue = dev_get_drvdata(musb->controller->parent); - void __iomem *usbss_base = glue->usbss_base; - - musb_writel(usbss_base, USBSS_IRQ_CLEARR, USBSS_IRQ_PD_COMP); - cppi41_dma_controller_destroy(c); -} - #ifdef CONFIG_PM_SLEEP static void dsps_dma_controller_suspend(struct dsps_glue *glue) { @@ -723,7 +713,7 @@ static struct musb_platform_ops dsps_ops = { #ifdef CONFIG_USB_TI_CPPI41_DMA .dma_init = dsps_dma_controller_create, - .dma_exit = dsps_dma_controller_destroy, + .dma_exit = cppi41_dma_controller_destroy, #endif .enable = dsps_musb_enable, .disable = dsps_musb_disable, diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index bd82fb9d17043327610c9193d28ef0d97b65fa13..70c5a7fef47867881711204568fd05c5467f3632 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -2001,6 +2001,9 @@ static void dr_swap(struct usbpd *pd) start_usb_host(pd, true); pd->current_dr = DR_DFP; + /* ensure host is started before allowing DP */ + extcon_blocking_sync(pd->extcon, EXTCON_USB_HOST, 0); + usbpd_send_svdm(pd, USBPD_SID, USBPD_SVDM_DISCOVER_IDENTITY, SVDM_CMD_TYPE_INITIATOR, 0, NULL, 0); } diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c index cf8f40ae6e017943c9ae97e50fca17d50304d51e..9b4354a00ca71d7377bb846390c6f346e6593e48 100644 --- a/drivers/usb/phy/phy-fsl-usb.c +++ b/drivers/usb/phy/phy-fsl-usb.c @@ -874,6 +874,7 @@ int usb_otg_start(struct platform_device *pdev) if (pdata->init && pdata->init(pdev) != 0) return -EINVAL; +#ifdef CONFIG_PPC32 if (pdata->big_endian_mmio) { _fsl_readl = _fsl_readl_be; _fsl_writel = _fsl_writel_be; @@ -881,6 +882,7 @@ int usb_otg_start(struct platform_device *pdev) _fsl_readl = _fsl_readl_le; _fsl_writel = _fsl_writel_le; } +#endif /* request irq */ p_otg->irq = platform_get_irq(pdev, 0); @@ -971,7 +973,7 @@ int usb_otg_start(struct platform_device *pdev) /* * state file in sysfs */ -static int show_fsl_usb2_otg_state(struct device *dev, +static ssize_t show_fsl_usb2_otg_state(struct device *dev, struct device_attribute *attr, char *buf) { struct otg_fsm *fsm = &fsl_otg_dev->fsm; diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c index 8f9b0499a83ff3aa9545b869e28eaa33800a896e..c64f2584b136f133da295e6fa8462b2a6c7473ed 100644 --- a/drivers/usb/phy/phy-msm-qusb-v2.c +++ b/drivers/usb/phy/phy-msm-qusb-v2.c @@ -467,7 +467,6 @@ static void qusb_phy_host_init(struct usb_phy *phy) dev_dbg(phy->dev, "QUSB2PHY_PLL_COMMON_STATUS_ONE:%x\n", reg); if (!(reg & CORE_READY_STATUS)) { dev_err(phy->dev, "QUSB PHY PLL LOCK fails:%x\n", reg); - WARN_ON(1); } } diff --git a/drivers/usb/phy/phy-msm-qusb.c b/drivers/usb/phy/phy-msm-qusb.c index 47db12bef9c64dc7ae95e776f3f0591a827300a0..aecb0e0e4f0fd8545d358a3355ba699bb625899e 100644 --- a/drivers/usb/phy/phy-msm-qusb.c +++ b/drivers/usb/phy/phy-msm-qusb.c @@ -606,7 +606,6 @@ static int qusb_phy_init(struct usb_phy *phy) if (pll_lock_fail) { dev_err(phy->dev, "QUSB PHY PLL LOCK fails:%x\n", reg); - WARN_ON(1); } return 0; diff --git a/drivers/usb/phy/phy-msm-ssusb-qmp.c b/drivers/usb/phy/phy-msm-ssusb-qmp.c index d61ca0d89c97db38c7fdee9ee70f1c0afcead237..b95986c458c23d74fca4f9653a705505ee135605 100644 --- a/drivers/usb/phy/phy-msm-ssusb-qmp.c +++ b/drivers/usb/phy/phy-msm-ssusb-qmp.c @@ -23,8 +23,10 @@ #include #include #include +#include #include #include +#include enum core_ldo_levels { CORE_LEVEL_NONE = 0, @@ -83,6 +85,10 @@ enum core_ldo_levels { /* USB3 Gen2 link training indicator */ #define RX_EQUALIZATION_IN_PROGRESS BIT(3) +#define USB3_DP_PCS_CDR_RESET_TIME 0x1DB0 +#define USB3_UNI_PCS_CDR_RESET_TIME 0x09B0 +#define USB3_DP_PCS_EQ_CONFIG5 0x1DEC +#define USB3_UNI_PCS_EQ_CONFIG5 0x09EC enum qmp_phy_rev_reg { USB3_PHY_PCS_STATUS, @@ -137,6 +143,8 @@ struct msm_ssphy_qmp { struct reset_control *phy_reset; struct reset_control *phy_phy_reset; struct reset_control *global_phy_reset; + struct extcon_dev *extcon_dp; + struct notifier_block dp_nb; bool power_enabled; bool clk_enabled; bool cable_connected; @@ -146,6 +154,10 @@ struct msm_ssphy_qmp { u32 *qmp_phy_init_seq; int init_seq_len; struct hrtimer timer; + + bool link_training_reset; + u32 cdr_reset_time_offset; + u32 eq_config5_offset; }; static const struct of_device_id msm_usb_id_table[] = { @@ -170,6 +182,7 @@ MODULE_DEVICE_TABLE(of, msm_usb_id_table); static void usb_qmp_powerup_phy(struct msm_ssphy_qmp *phy); static void msm_ssphy_qmp_enable_clks(struct msm_ssphy_qmp *phy, bool on); +static int msm_ssphy_qmp_link_training(struct usb_phy *uphy, bool start); static inline char *get_cable_status_str(struct msm_ssphy_qmp *phy) { @@ -375,9 +388,11 @@ static void usb_qmp_update_portselect_phymode(struct msm_ssphy_qmp *phy) switch (phy->phy.type) { case USB_PHY_TYPE_USB3_AND_DP: /* override hardware control for reset of qmp phy */ - writel_relaxed(SW_DPPHY_RESET_MUX | SW_DPPHY_RESET | - SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET, - phy->base + phy->phy_reg[USB3_DP_COM_RESET_OVRD_CTRL]); + if (!(phy->phy.flags & PHY_USB_DP_CONCURRENT_MODE)) + writel_relaxed(SW_DPPHY_RESET_MUX | SW_DPPHY_RESET | + SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET, + phy->base + + phy->phy_reg[USB3_DP_COM_RESET_OVRD_CTRL]); /* update port select */ if (val > 0) { @@ -387,11 +402,13 @@ static void usb_qmp_update_portselect_phymode(struct msm_ssphy_qmp *phy) phy->phy_reg[USB3_DP_COM_TYPEC_CTRL]); } - msm_ssphy_qmp_setmode(phy, USB3_DP_COMBO_MODE); + if (!(phy->phy.flags & PHY_USB_DP_CONCURRENT_MODE)) { + msm_ssphy_qmp_setmode(phy, USB3_DP_COMBO_MODE); - /* bring both QMP USB and QMP DP PHYs PCS block out of reset */ - writel_relaxed(0x00, - phy->base + phy->phy_reg[USB3_DP_COM_RESET_OVRD_CTRL]); + /* bring both USB and DP PHYs PCS block out of reset */ + writel_relaxed(0x00, phy->base + + phy->phy_reg[USB3_DP_COM_RESET_OVRD_CTRL]); + } break; case USB_PHY_TYPE_USB3_OR_DP: if (val > 0) { @@ -442,6 +459,30 @@ static void usb_qmp_powerup_phy(struct msm_ssphy_qmp *phy) mb(); } +static void usb_qmp_apply_link_training_workarounds(struct msm_ssphy_qmp *phy) +{ + uint32_t version, major, minor; + + if (!phy->link_training_reset) + return; + + version = socinfo_get_version(); + minor = SOCINFO_VERSION_MINOR(version); + major = SOCINFO_VERSION_MAJOR(version); + + /* sw workaround is needed only for hw reviosions below 2.1 */ + if ((major < 2) || (major == 2 && minor == 0)) { + writel_relaxed(0x52, phy->base + phy->eq_config5_offset); + phy->phy.link_training = msm_ssphy_qmp_link_training; + return; + } + + if (!phy->cdr_reset_time_offset) + return; + + writel_relaxed(0xA, phy->base + phy->cdr_reset_time_offset); +} + /* SSPHY Initialization */ static int msm_ssphy_qmp_init(struct usb_phy *uphy) { @@ -478,8 +519,11 @@ static int msm_ssphy_qmp_init(struct usb_phy *uphy) return ret; } + usb_qmp_apply_link_training_workarounds(phy); + /* perform software reset of PHY common logic */ - if (phy->phy.type == USB_PHY_TYPE_USB3_AND_DP) + if (phy->phy.type == USB_PHY_TYPE_USB3_AND_DP && + !(phy->phy.flags & PHY_USB_DP_CONCURRENT_MODE)) writel_relaxed(0x00, phy->base + phy->phy_reg[USB3_DP_COM_SW_RESET]); @@ -517,6 +561,25 @@ static int msm_ssphy_qmp_dp_combo_reset(struct usb_phy *uphy) phy); int ret = 0; + if (phy->phy.flags & PHY_USB_DP_CONCURRENT_MODE) { + dev_dbg(uphy->dev, "Resetting USB part of QMP phy\n"); + + /* Assert USB3 PHY CSR reset */ + ret = reset_control_assert(phy->phy_reset); + if (ret) { + dev_err(uphy->dev, "phy_reset assert failed\n"); + goto exit; + } + + /* Deassert USB3 PHY CSR reset */ + ret = reset_control_deassert(phy->phy_reset); + if (ret) { + dev_err(uphy->dev, "phy_reset deassert failed\n"); + goto exit; + } + return 0; + } + dev_dbg(uphy->dev, "Global reset of QMP DP combo phy\n"); /* Assert global PHY reset */ ret = reset_control_assert(phy->global_phy_reset); @@ -800,6 +863,56 @@ static int msm_ssphy_qmp_powerup(struct usb_phy *uphy, bool powerup) return 0; } +static int msm_ssphy_qmp_vbus_notifier(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + return 0; +} + +static int msm_ssphy_qmp_dp_notifier(struct notifier_block *nb, + unsigned long dp_lane, void *ptr) +{ + struct msm_ssphy_qmp *phy = container_of(nb, + struct msm_ssphy_qmp, dp_nb); + + if (dp_lane == 2 || dp_lane == 4) + phy->phy.flags |= PHY_USB_DP_CONCURRENT_MODE; + else + phy->phy.flags &= ~PHY_USB_DP_CONCURRENT_MODE; + + return 0; + +} + +static int msm_ssphy_qmp_extcon_register(struct msm_ssphy_qmp *phy, + struct device *dev) +{ + struct device_node *node = dev->of_node; + struct extcon_dev *edev; + int ret = 0; + + if (!of_property_read_bool(node, "extcon")) + return 0; + + edev = extcon_get_edev_by_phandle(dev, 0); + if (IS_ERR(edev)) { + dev_err(dev, "failed to get phandle for msm_ssphy_qmp\n"); + return PTR_ERR(edev); + } + + phy->extcon_dp = edev; + phy->phy.vbus_nb.notifier_call = msm_ssphy_qmp_vbus_notifier; + phy->dp_nb.notifier_call = msm_ssphy_qmp_dp_notifier; + ret = extcon_register_blocking_notifier(edev, EXTCON_DISP_DP, + &phy->dp_nb); + if (ret < 0) { + dev_err(dev, "failed to register blocking notifier\n"); + return ret; + } + + return 0; +} + static int msm_ssphy_qmp_get_clks(struct msm_ssphy_qmp *phy, struct device *dev) { int ret = 0; @@ -1102,15 +1215,25 @@ static int msm_ssphy_qmp_probe(struct platform_device *pdev) phy->phy.notify_connect = msm_ssphy_qmp_notify_connect; phy->phy.notify_disconnect = msm_ssphy_qmp_notify_disconnect; phy->phy.powerup = msm_ssphy_qmp_powerup; + phy->phy.reset = msm_ssphy_qmp_reset; - if (of_property_read_bool(dev->of_node, "qcom,link-training-reset")) - phy->phy.link_training = msm_ssphy_qmp_link_training; + if (phy->phy.type == USB_PHY_TYPE_USB3_AND_DP) { + phy->eq_config5_offset = USB3_DP_PCS_EQ_CONFIG5; + phy->cdr_reset_time_offset = USB3_DP_PCS_CDR_RESET_TIME; + phy->phy.reset = msm_ssphy_qmp_dp_combo_reset; + } + if (phy->phy.type == USB_PHY_TYPE_USB3) { + phy->eq_config5_offset = USB3_UNI_PCS_EQ_CONFIG5; + phy->cdr_reset_time_offset = USB3_UNI_PCS_CDR_RESET_TIME; + } - if (phy->phy.type == USB_PHY_TYPE_USB3_AND_DP) - phy->phy.reset = msm_ssphy_qmp_dp_combo_reset; - else - phy->phy.reset = msm_ssphy_qmp_reset; + phy->link_training_reset = of_property_read_bool(dev->of_node, + "qcom,link-training-reset"); + + ret = msm_ssphy_qmp_extcon_register(phy, dev); + if (ret) + goto err; ret = usb_add_phy_dev(&phy->phy); diff --git a/drivers/usb/serial/io_ti.h b/drivers/usb/serial/io_ti.h index 1bd67b24f9160a2d9b674151708c3fb5e13b2821..bc9ff5ebd67c1b5a1ab1ea4c4e619558c47f8c32 100644 --- a/drivers/usb/serial/io_ti.h +++ b/drivers/usb/serial/io_ti.h @@ -178,7 +178,7 @@ struct ump_interrupt { } __attribute__((packed)); -#define TIUMP_GET_PORT_FROM_CODE(c) (((c) >> 4) - 3) +#define TIUMP_GET_PORT_FROM_CODE(c) (((c) >> 6) & 0x01) #define TIUMP_GET_FUNC_FROM_CODE(c) ((c) & 0x0f) #define TIUMP_INTERRUPT_CODE_LSR 0x03 #define TIUMP_INTERRUPT_CODE_MSR 0x04 diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 3024b9b253605160a5f5e7038159bcc47ec4d1ea..75181d3afd958a81d2de0dfde24092481c089637 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -397,12 +397,20 @@ static int kobil_tiocmget(struct tty_struct *tty) transfer_buffer_length, KOBIL_TIMEOUT); - dev_dbg(&port->dev, "%s - Send get_status_line_state URB returns: %i. Statusline: %02x\n", - __func__, result, transfer_buffer[0]); + dev_dbg(&port->dev, "Send get_status_line_state URB returns: %i\n", + result); + if (result < 1) { + if (result >= 0) + result = -EIO; + goto out_free; + } + + dev_dbg(&port->dev, "Statusline: %02x\n", transfer_buffer[0]); result = 0; if ((transfer_buffer[0] & SUSBCR_GSL_DSR) != 0) result = TIOCM_DSR; +out_free: kfree(transfer_buffer); return result; } diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index d4124551fb56cacf50190ce9b10a7e1975701c46..0600dadd6a0c8e59b4af2242231c57e81959574c 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -199,6 +199,8 @@ static void option_instat_callback(struct urb *urb); #define DELL_PRODUCT_5800_V2_MINICARD_VZW 0x8196 /* Novatel E362 */ #define DELL_PRODUCT_5804_MINICARD_ATT 0x819b /* Novatel E371 */ +#define DELL_PRODUCT_5821E 0x81d7 + #define KYOCERA_VENDOR_ID 0x0c88 #define KYOCERA_PRODUCT_KPC650 0x17da #define KYOCERA_PRODUCT_KPC680 0x180a @@ -1033,6 +1035,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5800_MINICARD_VZW, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5800_V2_MINICARD_VZW, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5804_MINICARD_ATT, 0xff, 0xff, 0xff) }, + { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5821E), + .driver_info = RSVD(0) | RSVD(1) | RSVD(6) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) }, /* ADU-E100, ADU-310 */ { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_620UW) }, diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 34c5a75f98a750427a0fd4065060a3acddb8aec1..2153e67eeeeebc8eb5a962e687224cdc1374fc4e 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -55,6 +55,8 @@ static const struct usb_device_id id_table[] = { .driver_info = PL2303_QUIRK_ENDPOINT_HACK }, { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_UC485), .driver_info = PL2303_QUIRK_ENDPOINT_HACK }, + { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_UC232B), + .driver_info = PL2303_QUIRK_ENDPOINT_HACK }, { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID2) }, { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) }, { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) }, diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 123289085ee25974c1045adaa7fa56dd11198169..cec7141245ef6afb884dcc9b6d8ca53841f31805 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -29,6 +29,7 @@ #define ATEN_VENDOR_ID2 0x0547 #define ATEN_PRODUCT_ID 0x2008 #define ATEN_PRODUCT_UC485 0x2021 +#define ATEN_PRODUCT_UC232B 0x2022 #define ATEN_PRODUCT_ID2 0x2118 #define IODATA_VENDOR_ID 0x04bb diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 4c4ac4705ac03f8d850a653fe91e35b78bfe25b6..a9c5564b6b65bc7d25e4ef47b50e463731d54aa9 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -773,9 +773,9 @@ static void sierra_close(struct usb_serial_port *port) kfree(urb->transfer_buffer); usb_free_urb(urb); usb_autopm_put_interface_async(serial->interface); - spin_lock(&portdata->lock); + spin_lock_irq(&portdata->lock); portdata->outstanding_urbs--; - spin_unlock(&portdata->lock); + spin_unlock_irq(&portdata->lock); } sierra_stop_rx_urbs(port); diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 8fc3854e5e6967dc32f1a04e5ba95a304f10b683..57e9f6617084f4ae7aa62fafd9d8bcff6925549e 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -1123,7 +1123,7 @@ static void ti_break(struct tty_struct *tty, int break_state) static int ti_get_port_from_code(unsigned char code) { - return (code >> 4) - 3; + return (code >> 6) & 0x01; } static int ti_get_func_from_code(unsigned char code) diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c index 2674da40d9cd78d31c702a2b9b597639b02982a8..6d6acf2c07c368adbc2a275bd67ba3f119b05ae1 100644 --- a/drivers/usb/serial/usb-serial-simple.c +++ b/drivers/usb/serial/usb-serial-simple.c @@ -87,7 +87,8 @@ DEVICE(moto_modem, MOTO_IDS); /* Motorola Tetra driver */ #define MOTOROLA_TETRA_IDS() \ - { USB_DEVICE(0x0cad, 0x9011) } /* Motorola Solutions TETRA PEI */ + { USB_DEVICE(0x0cad, 0x9011) }, /* Motorola Solutions TETRA PEI */ \ + { USB_DEVICE(0x0cad, 0x9012) } /* MTP6550 */ DEVICE(motorola_tetra, MOTOROLA_TETRA_IDS); /* Novatel Wireless GPS driver */ diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 8cd2926fb1fe6f9a77fc8943beb5ac2eb3ddd40d..344ec8631481ee41dce9e7242f9063580bae696d 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -392,6 +392,15 @@ static int queuecommand_lck(struct scsi_cmnd *srb, return 0; } + if ((us->fflags & US_FL_NO_ATA_1X) && + (srb->cmnd[0] == ATA_12 || srb->cmnd[0] == ATA_16)) { + memcpy(srb->sense_buffer, usb_stor_sense_invalidCDB, + sizeof(usb_stor_sense_invalidCDB)); + srb->result = SAM_STAT_CHECK_CONDITION; + done(srb); + return 0; + } + /* enqueue the command and wake up the control thread */ srb->scsi_done = done; us->srb = srb; diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 33a6d624c8438b50e29c23bbf86af1cdf20d91d8..24de9c00d8e2498234fbc10887442950a1559977 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -842,6 +842,27 @@ static int uas_slave_configure(struct scsi_device *sdev) sdev->skip_ms_page_8 = 1; sdev->wce_default_on = 1; } + + /* + * Some disks return the total number of blocks in response + * to READ CAPACITY rather than the highest block number. + * If this device makes that mistake, tell the sd driver. + */ + if (devinfo->flags & US_FL_FIX_CAPACITY) + sdev->fix_capacity = 1; + + /* + * Some devices don't like MODE SENSE with page=0x3f, + * which is the command used for checking if a device + * is write-protected. Now that we tell the sd driver + * to do a 192-byte transfer with this command the + * majority of devices work fine, but a few still can't + * handle it. The sd driver will simply assume those + * devices are write-enabled. + */ + if (devinfo->flags & US_FL_NO_WP_DETECT) + sdev->skip_ms_page_3f = 1; + scsi_change_queue_depth(sdev, devinfo->qdepth - 2); return 0; } diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index d100290628bd26beb11991ebbcd8e6c84d6d719a..5e9b35a91431987e1c14dd57ebb7a38a669daa64 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -2307,6 +2307,13 @@ UNUSUAL_DEV( 0x2735, 0x100b, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_GO_SLOW ), +/* Reported-by: Tim Anderson */ +UNUSUAL_DEV( 0x2ca3, 0x0031, 0x0000, 0x9999, + "DJI", + "CineSSD", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_NO_ATA_1X), + /* * Reported by Frederic Marchal * Mio Moov 330 diff --git a/drivers/usb/wusbcore/security.c b/drivers/usb/wusbcore/security.c index 170f2c38de9b5695e37008c9dc975787f66021cb..5274aa7339b8fffc281e653134ccfdf57f99e790 100644 --- a/drivers/usb/wusbcore/security.c +++ b/drivers/usb/wusbcore/security.c @@ -230,7 +230,7 @@ int wusb_dev_sec_add(struct wusbhc *wusbhc, result = usb_get_descriptor(usb_dev, USB_DT_SECURITY, 0, secd, sizeof(*secd)); - if (result < sizeof(*secd)) { + if (result < (int)sizeof(*secd)) { dev_err(dev, "Can't read security descriptor or " "not enough data: %d\n", result); goto out; diff --git a/drivers/uwb/hwa-rc.c b/drivers/uwb/hwa-rc.c index 9a53912bdfe9f73d4b7de6a1d3b74dd8a94dc8b6..5d3ba747ae17a8882a959ff7be59309eecf11c36 100644 --- a/drivers/uwb/hwa-rc.c +++ b/drivers/uwb/hwa-rc.c @@ -873,6 +873,7 @@ static int hwarc_probe(struct usb_interface *iface, error_rc_add: usb_put_intf(iface); usb_put_dev(hwarc->usb_dev); + kfree(hwarc); error_alloc: uwb_rc_put(uwb_rc); error_rc_alloc: diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 244e5256c526f876b3afd2c41cdd333e7183dd4a..7ee3167bc083e6ea1c36bd0795240d84d520eb19 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -960,7 +960,7 @@ static void vhost_iotlb_notify_vq(struct vhost_dev *d, list_for_each_entry_safe(node, n, &d->pending_list, node) { struct vhost_iotlb_msg *vq_msg = &node->msg.iotlb; if (msg->iova <= vq_msg->iova && - msg->iova + msg->size - 1 > vq_msg->iova && + msg->iova + msg->size - 1 >= vq_msg->iova && vq_msg->type == VHOST_IOTLB_MISS) { vhost_poll_queue(&node->vq->poll); list_del(&node->node); @@ -1578,9 +1578,12 @@ int vhost_init_device_iotlb(struct vhost_dev *d, bool enabled) d->iotlb = niotlb; for (i = 0; i < d->nvqs; ++i) { - mutex_lock(&d->vqs[i]->mutex); - d->vqs[i]->iotlb = niotlb; - mutex_unlock(&d->vqs[i]->mutex); + struct vhost_virtqueue *vq = d->vqs[i]; + + mutex_lock(&vq->mutex); + vq->iotlb = niotlb; + __vhost_vq_meta_reset(vq); + mutex_unlock(&vq->mutex); } vhost_umem_clean(oiotlb); diff --git a/drivers/video/backlight/qcom-spmi-wled.c b/drivers/video/backlight/qcom-spmi-wled.c index a7393cce74ff04599f0c1d65cdb3e4d16c5b6d85..7e9a4d17b02875c93472b35de37f1e06ca65a5ee 100644 --- a/drivers/video/backlight/qcom-spmi-wled.c +++ b/drivers/video/backlight/qcom-spmi-wled.c @@ -278,6 +278,8 @@ static const u8 wled5_brt_wid_sel_reg[MOD_MAX] = { [MOD_B] = WLED5_SINK_MOD_B_BR_WID_SEL_REG, }; +static int wled_flash_setup(struct wled *wled); + static inline bool is_wled4(struct wled *wled) { if (*wled->version == WLED_PMI8998 || *wled->version == WLED_PM660L) @@ -833,6 +835,15 @@ static int wled_auto_calibrate(struct wled *wled) goto failed_calib; } + if (is_wled5(wled)) { + /* Update the flash sink configuration as well */ + rc = regmap_update_bits(wled->regmap, + wled->sink_addr + WLED5_SINK_FLASH_SINK_EN_REG, + WLED_SINK_CURR_SINK_MASK, sink_config); + if (rc < 0) + return rc; + } + /* MODULATOR_EN setting for valid sinks */ if (is_wled4(wled)) { for (i = 0; (string_cfg >> i) != 0; i++) { @@ -1065,6 +1076,11 @@ static int wled5_setup(struct wled *wled) u32 val; u8 string_cfg = wled->cfg.string_cfg; + rc = wled_flash_setup(wled); + if (rc < 0) + dev_err(&wled->pdev->dev, "failed to setup WLED flash/torch rc:%d\n", + rc); + rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED_CTRL_OVP, WLED5_CTRL_OVP_MASK, wled->cfg.ovp); @@ -1999,10 +2015,6 @@ static int wled_flash_setup(struct wled *wled) int rc, i; u8 val; - /* Not supported */ - if (is_wled4(wled)) - return 0; - /* Set FLASH_VREF_ADIM_HDIM to maximum */ rc = regmap_write(wled->regmap, wled->ctrl_addr + WLED5_CTRL_FLASH_HDRM_REG, 0xF); @@ -2359,11 +2371,6 @@ static int wled_probe(struct platform_device *pdev) return rc; } - rc = wled_flash_setup(wled); - if (rc < 0) - dev_err(&pdev->dev, "failed to setup WLED flash/torch rc:%d\n", - rc); - return rc; } diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 8634175da1fbf6e386ddea9741a4cd587e3e89af..f7f56121c746f09ca57cab536a3a855020e651cd 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -1734,12 +1734,12 @@ static int do_register_framebuffer(struct fb_info *fb_info) return 0; } -static int do_unregister_framebuffer(struct fb_info *fb_info) +static int unbind_console(struct fb_info *fb_info) { struct fb_event event; - int i, ret = 0; + int ret; + int i = fb_info->node; - i = fb_info->node; if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info) return -EINVAL; @@ -1754,17 +1754,29 @@ static int do_unregister_framebuffer(struct fb_info *fb_info) unlock_fb_info(fb_info); console_unlock(); + return ret; +} + +static int __unlink_framebuffer(struct fb_info *fb_info); + +static int do_unregister_framebuffer(struct fb_info *fb_info) +{ + struct fb_event event; + int ret; + + ret = unbind_console(fb_info); + if (ret) return -EINVAL; pm_vt_switch_unregister(fb_info->dev); - unlink_framebuffer(fb_info); + __unlink_framebuffer(fb_info); if (fb_info->pixmap.addr && (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) kfree(fb_info->pixmap.addr); fb_destroy_modelist(&fb_info->modelist); - registered_fb[i] = NULL; + registered_fb[fb_info->node] = NULL; num_registered_fb--; fb_cleanup_device(fb_info); event.info = fb_info; @@ -1777,7 +1789,7 @@ static int do_unregister_framebuffer(struct fb_info *fb_info) return 0; } -int unlink_framebuffer(struct fb_info *fb_info) +static int __unlink_framebuffer(struct fb_info *fb_info) { int i; @@ -1789,6 +1801,20 @@ int unlink_framebuffer(struct fb_info *fb_info) device_destroy(fb_class, MKDEV(FB_MAJOR, i)); fb_info->dev = NULL; } + + return 0; +} + +int unlink_framebuffer(struct fb_info *fb_info) +{ + int ret; + + ret = __unlink_framebuffer(fb_info); + if (ret) + return ret; + + unbind_console(fb_info); + return 0; } EXPORT_SYMBOL(unlink_framebuffer); diff --git a/drivers/video/fbdev/core/modedb.c b/drivers/video/fbdev/core/modedb.c index 2510fa728d77160326781219ec554ae50c99be4a..de119f11b78f964301ef9dafa4c3f1043b6e53e2 100644 --- a/drivers/video/fbdev/core/modedb.c +++ b/drivers/video/fbdev/core/modedb.c @@ -644,7 +644,7 @@ static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info, * * Valid mode specifiers for @mode_option: * - * x[M][R][-][@][i][m] or + * x[M][R][-][@][i][p][m] or * [-][@] * * with , , and decimal numbers and @@ -653,10 +653,10 @@ static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info, * If 'M' is present after yres (and before refresh/bpp if present), * the function will compute the timings using VESA(tm) Coordinated * Video Timings (CVT). If 'R' is present after 'M', will compute with - * reduced blanking (for flatpanels). If 'i' is present, compute - * interlaced mode. If 'm' is present, add margins equal to 1.8% - * of xres rounded down to 8 pixels, and 1.8% of yres. The char - * 'i' and 'm' must be after 'M' and 'R'. Example: + * reduced blanking (for flatpanels). If 'i' or 'p' are present, compute + * interlaced or progressive mode. If 'm' is present, add margins equal + * to 1.8% of xres rounded down to 8 pixels, and 1.8% of yres. The chars + * 'i', 'p' and 'm' must be after 'M' and 'R'. Example: * * 1024x768MR-8@60m - Reduced blank with margins at 60Hz. * @@ -697,7 +697,8 @@ int fb_find_mode(struct fb_var_screeninfo *var, unsigned int namelen = strlen(name); int res_specified = 0, bpp_specified = 0, refresh_specified = 0; unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0; - int yres_specified = 0, cvt = 0, rb = 0, interlace = 0; + int yres_specified = 0, cvt = 0, rb = 0; + int interlace_specified = 0, interlace = 0; int margins = 0; u32 best, diff, tdiff; @@ -748,9 +749,17 @@ int fb_find_mode(struct fb_var_screeninfo *var, if (!cvt) margins = 1; break; + case 'p': + if (!cvt) { + interlace = 0; + interlace_specified = 1; + } + break; case 'i': - if (!cvt) + if (!cvt) { interlace = 1; + interlace_specified = 1; + } break; default: goto done; @@ -819,11 +828,21 @@ int fb_find_mode(struct fb_var_screeninfo *var, if ((name_matches(db[i], name, namelen) || (res_specified && res_matches(db[i], xres, yres))) && !fb_try_mode(var, info, &db[i], bpp)) { - if (refresh_specified && db[i].refresh == refresh) - return 1; + const int db_interlace = (db[i].vmode & + FB_VMODE_INTERLACED ? 1 : 0); + int score = abs(db[i].refresh - refresh); + + if (interlace_specified) + score += abs(db_interlace - interlace); + + if (!interlace_specified || + db_interlace == interlace) + if (refresh_specified && + db[i].refresh == refresh) + return 1; - if (abs(db[i].refresh - refresh) < diff) { - diff = abs(db[i].refresh - refresh); + if (score < diff) { + diff = score; best = i; } } diff --git a/drivers/video/fbdev/goldfishfb.c b/drivers/video/fbdev/goldfishfb.c index 1e56b50e408234f826fd28fdaa1bee0807911dcf..8c93ad1dd9cc899a9ce492797f81a4c3ce4aa211 100644 --- a/drivers/video/fbdev/goldfishfb.c +++ b/drivers/video/fbdev/goldfishfb.c @@ -302,6 +302,7 @@ static int goldfish_fb_remove(struct platform_device *pdev) dma_free_coherent(&pdev->dev, framesize, (void *)fb->fb.screen_base, fb->fb.fix.smem_start); iounmap(fb->reg_base); + kfree(fb); return 0; } diff --git a/drivers/video/fbdev/msm/Makefile b/drivers/video/fbdev/msm/Makefile index 09f874f1d956fcb2a4b49d2736fd883ac9123b7a..35b2a0fbb4087e770dede4fa7bdf6023655f020d 100644 --- a/drivers/video/fbdev/msm/Makefile +++ b/drivers/video/fbdev/msm/Makefile @@ -56,7 +56,8 @@ obj-$(CONFIG_FB_MSM_MDSS_EDP_PANEL) += mdss_edp_aux.o obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_tx.o obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_panel.o -obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_hdcp.o +obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdcp_1x.o +obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdcp_2x.o obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_hdcp2p2.o obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_cec.o obj-$(CONFIG_FB_MSM_MDSS_HDMI_PANEL) += mdss_hdmi_audio.o diff --git a/drivers/video/fbdev/msm/mdss_cec_core.c b/drivers/video/fbdev/msm/mdss_cec_core.c index 23a3ce55c2d62f68302b48d6678bb7c40095a825..b072ca4c22c662a556a4c605b43d81213fa0c7c7 100644 --- a/drivers/video/fbdev/msm/mdss_cec_core.c +++ b/drivers/video/fbdev/msm/mdss_cec_core.c @@ -50,7 +50,7 @@ static struct cec_ctl *cec_get_ctl(struct device *dev) struct mdss_panel_info *pinfo; if (!dev) { - pr_err("invalid input\n"); + pr_err("invalid device\n"); goto error; } @@ -83,8 +83,13 @@ static int cec_msg_send(struct cec_ctl *ctl, struct cec_msg *msg) int ret = -EINVAL; struct cec_ops *ops; - if (!ctl || !msg) { - pr_err("invalid input\n"); + if (!ctl) { + pr_err("invalid cec ctl\n"); + goto end; + } + + if (!msg) { + pr_err("invalid cec message\n"); goto end; } @@ -101,8 +106,13 @@ static void cec_dump_msg(struct cec_ctl *ctl, struct cec_msg *msg) int i; unsigned long flags; - if (!ctl || !msg) { - pr_err("invalid input\n"); + if (!ctl) { + pr_err("invalid cec ctl\n"); + return; + } + + if (!msg) { + pr_err("invalid cec message\n"); return; } @@ -136,7 +146,7 @@ static int cec_disable(struct cec_ctl *ctl) struct cec_ops *ops; if (!ctl) { - pr_err("Invalid input\n"); + pr_err("invalid cec ctl\n"); goto end; } @@ -165,7 +175,7 @@ static int cec_enable(struct cec_ctl *ctl) struct cec_ops *ops; if (!ctl) { - pr_err("Invalid input\n"); + pr_err("invalid cec ctl\n"); goto end; } @@ -189,8 +199,13 @@ static int cec_send_abort_opcode(struct cec_ctl *ctl, int i = 0; struct cec_msg out_msg; - if (!ctl || !in_msg) { - pr_err("Invalid input\n"); + if (!ctl) { + pr_err("invalid cec ctl\n"); + return -EINVAL; + } + + if (!in_msg) { + pr_err("invalid cec message\n"); return -EINVAL; } @@ -209,10 +224,14 @@ static int cec_msg_parser(struct cec_ctl *ctl, struct cec_msg *in_msg) int rc = 0, i = 0; struct cec_msg out_msg; - if (!ctl || !in_msg) { - pr_err("Invalid input\n"); - rc = -EINVAL; - goto end; + if (!ctl) { + pr_err("invalid cec ctl\n"); + return -EINVAL; + } + + if (!in_msg) { + pr_err("invalid cec message\n"); + return -EINVAL; } pr_debug("in_msg->opcode = 0x%x\n", in_msg->opcode); @@ -345,7 +364,7 @@ static int cec_msg_recv(void *data, struct cec_msg *msg) int ret = 0; if (!ctl) { - pr_err("invalid input\n"); + pr_err("invalid cec ctl\n"); ret = -EINVAL; goto end; } @@ -395,7 +414,7 @@ static ssize_t cec_rda_enable(struct device *dev, struct cec_ctl *ctl = cec_get_ctl(dev); if (!ctl) { - pr_err("Invalid input\n"); + pr_err("invalid cec ctl\n"); ret = -EINVAL; goto end; } @@ -423,7 +442,7 @@ static ssize_t cec_wta_enable(struct device *dev, struct cec_ops *ops; if (!ctl) { - pr_err("Invalid input\n"); + pr_err("invalid cec ctl\n"); ret = -EINVAL; goto end; } @@ -475,7 +494,7 @@ static ssize_t cec_rda_enable_compliance(struct device *dev, struct cec_ctl *ctl = cec_get_ctl(dev); if (!ctl) { - pr_err("Invalid ctl\n"); + pr_err("invalid cec ctl\n"); return -EINVAL; } @@ -497,7 +516,7 @@ static ssize_t cec_wta_enable_compliance(struct device *dev, struct cec_ops *ops; if (!ctl) { - pr_err("Invalid ctl\n"); + pr_err("invalid cec ctl\n"); ret = -EINVAL; goto end; } @@ -543,7 +562,7 @@ static ssize_t cec_rda_logical_addr(struct device *dev, struct cec_ctl *ctl = cec_get_ctl(dev); if (!ctl) { - pr_err("Invalid ctl\n"); + pr_err("invalid cec ctl\n"); return -EINVAL; } @@ -564,7 +583,7 @@ static ssize_t cec_wta_logical_addr(struct device *dev, struct cec_ops *ops; if (!ctl) { - pr_err("Invalid ctl\n"); + pr_err("invalid cec ctl\n"); ret = -EINVAL; goto end; } @@ -578,7 +597,7 @@ static ssize_t cec_wta_logical_addr(struct device *dev, } if (logical_addr < 0 || logical_addr > 15) { - pr_err("Invalid logical address\n"); + pr_err("invalid logical address\n"); ret = -EINVAL; goto end; } @@ -604,7 +623,7 @@ static ssize_t cec_rda_msg(struct device *dev, ssize_t ret; if (!ctl) { - pr_err("Invalid ctl\n"); + pr_err("invalid cec ctl\n"); ret = -EINVAL; goto end; } @@ -660,7 +679,7 @@ static ssize_t cec_wta_msg(struct device *dev, struct cec_ctl *ctl = cec_get_ctl(dev); if (!ctl) { - pr_err("Invalid ctl\n"); + pr_err("invalid cec ctl\n"); ret = -EINVAL; goto end; } @@ -763,7 +782,7 @@ void *cec_abstract_init(struct cec_abstract_init_data *init_data) int ret = 0; if (!init_data) { - pr_err("invalid input\n"); + pr_err("invalid cec abstract init data\n"); ret = -EINVAL; goto end; } diff --git a/drivers/video/fbdev/msm/mdss_dba_utils.c b/drivers/video/fbdev/msm/mdss_dba_utils.c index b920d2e1d7cf7c7e21c7d1a23ec1f05e2ea42d55..f56667f2f01d856a248d115c154d87e55d8108d8 100644 --- a/drivers/video/fbdev/msm/mdss_dba_utils.c +++ b/drivers/video/fbdev/msm/mdss_dba_utils.c @@ -298,7 +298,7 @@ static bool mdss_dba_check_audio_support(struct mdss_dba_utils_data *udata) { bool dvi_mode = false; int audio_blk_size = 0; - struct msm_hdmi_audio_edid_blk audio_blk; + struct msm_ext_disp_audio_edid_blk audio_blk; if (!udata) { pr_debug("%s: Invalid input\n", __func__); @@ -307,7 +307,7 @@ static bool mdss_dba_check_audio_support(struct mdss_dba_utils_data *udata) memset(&audio_blk, 0, sizeof(audio_blk)); /* check if sink is in DVI mode */ - dvi_mode = !hdmi_edid_get_sink_mode(udata->edid_data); + dvi_mode = hdmi_edid_is_dvi_mode(udata->edid_data); /* get the audio block size info from EDID */ hdmi_edid_get_audio_blk(udata->edid_data, &audio_blk); @@ -328,7 +328,7 @@ static void mdss_dba_utils_dba_cb(void *data, enum msm_dba_callback_event event) bool operands_present = false; u32 no_of_operands, size, i; u32 operands_offset = MAX_CEC_FRAME_SIZE - MAX_OPERAND_SIZE; - struct msm_hdmi_audio_edid_blk blk; + struct msm_ext_disp_audio_edid_blk blk; if (!udata) { pr_err("Invalid data\n"); @@ -578,7 +578,7 @@ int mdss_dba_utils_video_on(void *data, struct mdss_panel_info *pinfo) video_cfg.h_pulse_width = pinfo->lcdc.h_pulse_width; video_cfg.v_pulse_width = pinfo->lcdc.v_pulse_width; video_cfg.pclk_khz = (unsigned long)pinfo->clk_rate / 1000; - video_cfg.hdmi_mode = hdmi_edid_get_sink_mode(ud->edid_data); + video_cfg.hdmi_mode = !hdmi_edid_is_dvi_mode(ud->edid_data); /* Calculate number of DSI lanes configured */ video_cfg.num_of_input_lanes = 0; diff --git a/drivers/video/fbdev/msm/mdss_hdcp.h b/drivers/video/fbdev/msm/mdss_hdcp.h new file mode 100644 index 0000000000000000000000000000000000000000..5edb3b54000bc3c7725fa04903c67b82bf9f1483 --- /dev/null +++ b/drivers/video/fbdev/msm/mdss_hdcp.h @@ -0,0 +1,87 @@ +/* Copyright (c) 2012, 2014-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MDSS_HDCP_H__ +#define __MDSS_HDCP_H__ + +#include